从这里开始

  A < B < E < D < C = F,心情简单.jpg。

Problem A ><

  把峰谷都设成 0。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 5e5 + 5; int n;
char s[N];
int L[N], R[N]; int main() {
scanf("%s", s + 1);
n = strlen(s + 1) + 1;
for (int i = 1; i <= n; i++)
L[i] = (s[i - 1] == '<') * (L[i - 1] + 1);
for (int i = n; i; i--)
R[i] = (s[i] == '>') * (R[i + 1] + 1);
long long ans = 0;
for (int i = 1; i <= n; i++) {
ans += max(L[i], R[i]);
// cerr << max(L[i], R[i]) << ' ';
}
printf("%lld\n", ans);
return 0;
}

Problem B Two Contests

  考虑如果两个区间有包含,要么它们放在一起,要么长的那一个单独在一场考试。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 1e5 + 5; const int inf = (signed) (~0u >> 2); typedef class Segment {
public:
int l, r; Segment() { }
Segment(int l, int r) : l(l), r(r) { } Segment operator & (Segment b) const {
return Segment(max(l, b.l), min(r, b.r));
}
int length() {
return max(r - l + 1, 0);
}
boolean operator < (Segment b) const {
return r < b.r;
}
} Segment; int n;
Segment s[N], sl[N], sr[N]; int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &s[i].l, &s[i].r);
}
sort(s + 1, s + n + 1);
int ans = 0;
sl[0] = Segment(0, inf);
for (int i = 1; i <= n; i++)
sl[i] = sl[i - 1] & s[i];
sr[n + 1] = Segment(0, inf);
for (int i = n; i; i--)
sr[i] = sr[i + 1] & s[i];
for (int i = 1; i < n; i++)
ans = max(ans, sl[i].length() + sr[i + 1].length());
for (int i = 1; i <= n; i++)
ans = max(ans, s[i].length() + (sl[i - 1] & sr[i + 1]).length());
printf("%d\n", ans);
return 0;
}

Problem C Neither AB nor BA

  考虑把奇数位置上的 A 变成 B,B 变成 A,那么现在变成只有 AA 和 BB 不能消除。

  考虑能够消除所有字符的必要条件是 A 或者 B 的数量不超过 $n / 2$。不难发现这个条件也是充分的。

  如果不存在 C,那么直接消除 AB 即可。

  考虑如果 C 只与 A 或者 B 相邻,那么先把 AB 相互消除,最后和 C 消除,如果还剩一些 C,那么把 C 两两消除。因为 A,B 的数量都不超过 $n / 2$,所以它们相互消除后剩下的字符数量不会超过 C 的数量。

  否则如果 A,B 的数量一样多,那么至少有 2 个 C,消除 1 个 AC 和 1 个 BC,否则把 C 和较多一个字符消除。显然这样仍然满足条件,可以递归到 $n$ 更小的问题。

  然后直接计数就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long void exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
} else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < 0) ? (x + n) : (x);
} const int Mod = 998244353; template <const int Mod = :: Mod>
class Z {
public:
int v; Z() : v(0) { }
Z(int x) : v(x){ }
Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) {
int x;
return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
}
friend Z operator - (const Z& a, const Z& b) {
int x;
return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
}
friend Z operator * (const Z& a, const Z& b) {
return Z(a.v * 1ll * b.v);
}
friend Z operator ~(const Z& a) {
return inv(a.v, Mod);
}
friend Z operator - (const Z& a) {
return Z(0) - a;
}
Z& operator += (Z b) {
return *this = *this + b;
}
Z& operator -= (Z b) {
return *this = *this - b;
}
Z& operator *= (Z b) {
return *this = *this * b;
}
friend boolean operator == (const Z& a, const Z& b) {
return a.v == b.v;
}
}; Z<> qpow(Z<> a, int p) {
Z<> rt = Z<>(1), pa = a;
for ( ; p; p >>= 1, pa = pa * pa) {
if (p & 1) {
rt = rt * pa;
}
}
return rt;
} typedef Z<> Zi; const int N = 1e7 + 7; int n;
Zi fac[N], _fac[N], pw2[N]; Zi comb(int n, int m) {
return (n < m) ? (0) : (fac[n] * _fac[m] * _fac[n - m]);
} int main() {
scanf("%d", &n);
fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i;
_fac[n] = ~fac[n];
for (int i = n; i; i--)
_fac[i - 1] = _fac[i] * i;
pw2[0] = 1;
for (int i = 1; i <= n + 1; i++)
pw2[i] = pw2[i - 1] + pw2[i - 1];
Zi ans = qpow(3, n);
for (int i = (n >> 1) + 1; i <= n; i++)
ans -= comb(n, i) * pw2[n - i + 1];
printf("%d\n", ans.v);
return 0;
}

Problem D Balance Beam

  一道贪心题就有 100 种假贪心。

  假设我们已经定好了顺序,设 $B_i - A_i$ 的前缀 max 为 $mx$,显然答案可以这样计算

for (int i = 1; i <= n; i++) {
if (sum >= B[i]) {
sum -= B[i];
ans += 1;
} else {
ans += 1.0 * sum / B[i];
break;
}
}

  考虑枚举进入 else 语句的 $i$。计算贡献可以分为 3 部分:$[1, i), (i, pmx], (pmx, n]$,其中 $pmx$ 表示前缀 max 的位置。先考虑把所有 $A_i < B_i$ 的平衡木加入 $i$ 之后 $pmx$ 之前,然后考虑把一些移动到 i 之前,不难发现移动的代价为 $\max\{A_i, B_i\}$。排序后二分一下最多能选到哪即可。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long
#define ld long double template <typename T>
boolean vmax(T& a, T b) {
return (a < b) ? (a = b, true) : (false);
} const int N = 1e5 + 5;
const ll llf = 1e17;
const int inf = (signed) (~0u >> 2); ll gcd(ll a, ll b) {
return (b) ? (gcd(b, a % b)) : (a);
} typedef class Fraction {
public:
ll a, b; Fraction() : a(0), b(1) { }
Fraction(ll a, ll b) : a(a), b(b) { } boolean operator < (Fraction B) const {
return ((ld) a) * B.b - ((ld) b) * B.a < 0;
}
boolean operator > (Fraction B) const {
return ((ld) a) * B.b - ((ld) b) * B.a > 0;
}
} Fraction; #define pii pair<int, int> typedef class Item {
public:
int a, b, id; Item() { }
Item(int a, int b, int id) : a(a), b(b), id(id) { } int maxval() const {
return max(a, b);
}
boolean operator < (Item i) const {
return maxval() < i.maxval();
}
} Item; int n;
vector<Item> E;
ll _presum[N], *presum; int main() {
scanf("%d", &n);
ll _sum = 0;
for (int i = 1, a, b; i <= n; i++) {
scanf("%d%d", &a, &b);
E.emplace_back(a, b, i);
_sum += max(b - a, 0);
}
sort(E.begin(), E.end());
Fraction ans (0, 1), I (1, 1);
presum = _presum + 1;
presum[-1] = 0;
for (int i = 0; i < n; i++)
presum[i] = presum[i - 1] + E[i].maxval();
for (int j = 0; j < n; j++) {
ll sum = _sum, ts;
Item& e = E[j];
if (e.a > e.b)
sum += e.b - e.a;
int l = 0, r = n - 1, mid;
#define calc(p) (presum[p] - (p >= j) * e.maxval())
while (l <= r) {
mid = (l + r) >> 1;
ts = calc(mid);
if (ts <= sum) {
l = mid + 1;
} else {
r = mid - 1;
}
}
Fraction tmp (sum - calc(l - 1), e.b);
tmp = min(tmp, I);
tmp.a += tmp.b * (l - (l > j));
ans = max(ans, tmp);
}
ll g = gcd(ans.a, ans.b *= n);
ans.a /= g;
ans.b /= g;
printf("%lld %lld\n", ans.a, ans.b);
return 0;
}

Problem E Prefix Suffix Addition

  显然可以让前缀加非 0 的位置不相交,后缀加非 0 的位置不相交,并且不会更劣。

  问题等价于把原序列拆成两个序列 $\{x_i\}, \{y_i\}$,满足

  • $x_0 = y_0 = x_{n + 1} = y_{n + 1} = 0$

  • $x_i \geqslant 0, y_i \geqslant 0, x_i + y_i = a_i$。

  要求最小化 $\sum [x_i > x_{i + 1}] + [y_i < y_{i + 1}]$。

  设 $f_{i, j}$ 表示考虑到序列的第 $i$ 位,$x_i$ 的值为 $j$ 的最小代价。

  不难发现两个性质:

  • $f_{i, j}$ 的极差小于等于 2
  • $f_{i, j}$ 单调不增

  然后记录一下分界点,转移二分一下就行了。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 2e5 + 5; typedef class dp_t {
public:
int v0, p1, p2, a; dp_t() { }
dp_t(int v0, int p1, int p2, int a) : v0(v0), p1(p1), p2(p2), a(a) { } int eval(int x, int na) {
#define calc(xls, fold) ((fold) + (xls > x) + (a - xls < na - x))
int rt = calc(0, v0);
if (p1 <= a)
rt = min(rt, calc(p1, v0 - 1));
if (p2 <= a)
rt = min(rt, calc(p2, v0 - 2));
return rt;
}
dp_t trans(int na) {
dp_t rt (0, 0, 0, na);
rt.v0 = eval(0, na);
int l = 0, r = na, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (eval(mid, na) == rt.v0) {
l = mid + 1;
} else {
r = mid - 1;
}
}
rt.p1 = l;
r = na;
while (l <= r) {
mid = (l + r) >> 1;
if (eval(mid, na) == rt.v0 - 1) {
l = mid + 1;
} else {
r = mid - 1;
}
}
rt.p2 = l;
return rt;
}
} dp_t; int n;
int a[N]; int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
dp_t f (0, 1, 1, 0);
for (int i = 1; i <= n; i++)
f = f.trans(a[i]);
f = f.trans(0);
printf("%d\n", f.v0);
return 0;
}

Problem F Two Pieces

  考虑用 $(x, d)$ 来表示一个状态,其中较大数在 $x$,较小数和较大数的差为 $d$。那么可以通过一些限制转化成求操作序列个数,有如下三种操作:

  • 将 $x, d$ 同时加上 1
  • 将 $d$ 减少 1,这个时候必须满足 $d \geqslant 2$
  • 将 $d$ 设为 0.

  你发现前面两个操作"很 Catalan",考虑确定前两个操作序列,然后插入第三种操作。

  不难发现第 1 种操作会恰好执行 $B$ 次,考虑枚举第 $2$ 种操作的操作次数 $k$。然后能用折线法计算方案数。

  如果 $N = B + k$,这种情况很 trivial,可以直接做。否则考虑 $B + k < N$ 的情况。

  考虑如何插入第 3 种操作,注意到它插入后必须同时满足两个条件:

  • 纵坐标到达 $B - A$。
  • 不会使第二种操作不合法。

  注意到它的影响相当于把一段后缀的 $d$ 减去其中第一个 $d$ 的值。所以为了满足第二个条件它必须是严格的后缀最小值,为了满足第一个条件它需要操作最后一个 $d = A - k$。

  满足这之后,可以把操作 3 插入任意一个满足 $d \leqslant A - k$ 的严格后缀最小值处。这个直接插板法算方案即可。

Code

#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long void exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
} else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < 0) ? (x + n) : (x);
} const int Mod = 998244353; template <const int Mod = :: Mod>
class Z {
public:
int v; Z() : v(0) { }
Z(int x) : v(x){ }
Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) {
int x;
return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
}
friend Z operator - (const Z& a, const Z& b) {
int x;
return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
}
friend Z operator * (const Z& a, const Z& b) {
return Z(a.v * 1ll * b.v);
}
friend Z operator ~(const Z& a) {
return inv(a.v, Mod);
}
friend Z operator - (const Z& a) {
return Z(0) - a;
}
Z& operator += (Z b) {
return *this = *this + b;
}
Z& operator -= (Z b) {
return *this = *this - b;
}
Z& operator *= (Z b) {
return *this = *this * b;
}
friend boolean operator == (const Z& a, const Z& b) {
return a.v == b.v;
}
}; Z<> qpow(Z<> a, int p) {
Z<> rt = Z<>(1), pa = a;
for ( ; p; p >>= 1, pa = pa * pa) {
if (p & 1) {
rt = rt * pa;
}
}
return rt;
} typedef Z<> Zi; const int N = 2e7 + 7; int n, A, B;
Zi fac[N], _fac[N]; void init(int n) {
fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i;
_fac[n] = ~fac[n];
for (int i = n; i; i--)
_fac[i - 1] = _fac[i] * i;
}
Zi comb(int n, int m) {
return (n < m) ? (0) : (fac[n] * _fac[m] * _fac[n - m]);
}
Zi calc(int x, int y) {
return comb(x + y, x) - comb(x + y, x + 1);
} int main() {
scanf("%d%d%d", &n, &A, &B);
if (!B) {
puts("1");
return 0;
}
init(n << 1);
Zi ans = 0;
for (int k = 0; k <= n - B && k <= A; k++) {
if (B + k == n) {
ans += (A == k) * calc(B - 1, A);
} else {
ans += calc(B - 1, k) * comb(n - B - k - 1 + A - k, A - k);
}
}
printf("%d\n", ans.v);
return 0;
}

AtCoder Grand Contest 040 简要题解的更多相关文章

  1. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  2. AtCoder Grand Contest 039 简要题解

    从这里开始 比赛目录 Problem A Connection and Disconnection 简单讨论即可. Code #include <bits/stdc++.h> using ...

  3. AtCoder Grand Contest 035 简要题解

    从这里开始 题目目录 Problem A XOR Circle 你发现,权值的循环节为 $a_0, a_1, a_0\oplus a_1$,然后暴力即可. Code #include <bits ...

  4. AtCoder Grand Contest 036 简要题解

    从这里开始 比赛目录 Problem A Triangle 考虑把三角形移到和坐标轴相交,即 然后能够用坐标比较简单地计算面积,简单构造一下就行了. Code #include <bits/st ...

  5. AtCoder Grand Contest 037 简要题解

    从这里开始 题目目录 Problem A Dividing a String 猜想每段长度不超过2.然后dp即可. 考虑最后一个长度大于等于3的一段,如果划成$1 + 2$会和后面相同,那么划成$2 ...

  6. AtCoder Grand Contest 038 简要题解

    从这里开始 比赛目录 Problem A 01 Matrix Code #include <bits/stdc++.h> using namespace std; typedef bool ...

  7. AtCoder Grand Contest 021完整题解

    提示:如果公式挂了请多刷新几次,MathJex的公式渲染速度并不是那么理想. 总的来说,还是自己太弱了啊.只做了T1,还WA了两发.今天还有一场CodeForces,晚上0点qwq... 题解还是要好 ...

  8. AtCoder Grand Contest 040

    Preface 今年准备省选啥都不说了,省选题基本上都做过一遍了,开始尝试板刷AGC 这场做完就从AGC001开始吧,感觉以我的速度和来机房的频率一个礼拜做一场都谢天谢地了 A - >< ...

  9. 2018.09.08 AtCoder Beginner Contest 109简要题解

    比赛传送门 水题大赛? 全是水题啊!!! T1 ABC333 就是判断是不是两个数都是奇数就行了. 代码: #include<bits/stdc++.h> using namespace ...

随机推荐

  1. hdu-6071 Lazy Running

    In HDU, you have to run along the campus for 24 times, or you will fail in PE. According to the rule ...

  2. linux bash 的基础语法

    示例均来自网络,附带有原始链接地址,自己练习整理发出,均测试可用 linux shell 基本语法 - 周学伟 - 博客园 https://www.cnblogs.com/zxouxuewei/p/6 ...

  3. 使用 jQuery.TypeAhead 让文本框自动完成 (一)(最简单的用法)

    项目地址:https://github.com/twitter/typeahead.js 直接贴代码了: @section headSection { <script type="te ...

  4. 在进行机器学习建模时,为什么需要验证集(validation set)?

    在进行机器学习建模时,为什么需要评估集(validation set)? 笔者最近有一篇文章被拒了,其中有一位审稿人提到论文中的一个问题:”应该在验证集上面调整参数,而不是在测试集“.笔者有些不明白为 ...

  5. 【论文阅读】Objects as Points 又名 CenterNet | 目标检测

    目录 Abstract Instruction 分析 CenterNet 的Loss公式 第一部分:\(L_k\) 第二部分:\(L_{size}\) 第三部分:\(L_{off}\) Abstrac ...

  6. C#与vb.net源码代码互转网站

    该转换器是印度开发团队推出的,推出时间也挺长,仅支持C#和VB.net代码转换.代码转换地址: C# -> VB.NET  http://www.dotnetspider.com/convert ...

  7. Java生鲜电商平台-库存管理设计与架构

    Java生鲜电商平台-库存管理设计与架构 WMS的功能: 1.业务批次管理 该功能提供完善的物料批次信息.批次管理设置.批号编码规则设置.日常业务处理.报表查询,以及库存管理等综合批次管理功能,使企业 ...

  8. Spring循环依赖原因及如何解决

    浅谈Spring解决循环依赖的三种方式 SpringBoot构造器注入循环依赖及解决 原文:https://www.baeldung.com/circular-dependencies-in-spri ...

  9. 运算符 &(与运算)、|(或运算)、^(异或运算)

    按位与运算符(&) 参加运算的两个数据,按二进制位进行“与”运算. 运算规则:0&0=0;  0&1=0;   1&0=0;    1&1=1; 按位或运算符( ...

  10. 电信NBIOT 3 - 数据下行

    电信NBIOT 1 - 数据上行(中国电信开发者平台对接流程) 电信NBIOT 2 - 数据上行(中间件获取电信消息通知) 电信NBIOT 3 - 数据下行 电信NBIOT 4 - NB73模块上行测 ...