从这里开始

  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. 升级 ASP.NET Core 3.0 设置 JSON 返回 PascalCase 格式与 SignalR 问题

    由于一些 JS 组件要求 JSON 格式是 PascalCase 格式,新版本 ASP.NET Core 3.0 中默认移除了 Newtonsoft.Json ,使用了微软自己实现的 System.T ...

  2. Logstash:Data转换,分析,提取,丰富及核心操作

    Logstash:Data转换,分析,提取,丰富及核心操作 Logstash plugins Logstash是一个非常容易进行扩张的框架.它可以对各种的数据进行分析处理.这依赖于目前提供的超过200 ...

  3. Python - 条件控制、循环语句 - 第十二天

    Python 条件控制.循环语句 end 关键字 关键字end可以用于将结果输出到同一行,或者在输出的末尾添加不同的字符,实例如下: Python 条件语句是通过一条或多条语句的执行结果(True 或 ...

  4. 在React中使用react-router-dom路由

    1,路由组件的基本实现 使用React构建的单页面应用,要想实现页面间的跳转,首先想到的就是使用路由.在React中,常用的有两个包可以实现这个需求,那就是react-router和react-rou ...

  5. 将多个sass文件合并到一个文件中

    将多个sass文件合并到一个文件中 应用场景:制作angular npm包的时候,定义的一些全局样式,自定义主题色这类的情况下,多个scss文件会要合并成一个文件并写到dist文件里,发布到仓库中. ...

  6. python基础编程——类和实例

    在了解类和实例之前,需要先了解什么是面向对象,什么又是面向过程.面向过程是以过程为中心实现一步步操作(相互调用,类似流水线思想):面向对象是以事物为中心,某个事物可以拥有自己的多个行为,而另一个事物也 ...

  7. jvm默认的并行垃圾回收器和G1垃圾回收器性能对比

    http://www.importnew.com/13827.html 参数如下: JAVA_OPTS="-server -Xms1024m -Xmx1024m -Xss256k -XX:M ...

  8. 基于Proxy的小程序状态管理

    摘要: 小程序状态管理. 作者:wwayne 原文:基于Proxy的小程序状态管理 Fundebug经授权转载,版权归原作者所有. 微信小程序的市场在进一步的扩大,而背后的技术社区仍在摸索着最好的实践 ...

  9. IntelliJ IDEA 中使用 Lambok (注解无效问题的解决)

    一,概述 Lambok可以说一个能很大提高开发效率的插件,只要在使用注解的方式就能实现很多常用的功能.如常用的@Data能在编译阶段自动生成toString方法,getter方法setter方法等. ...

  10. C语言之整除

    除法运算符:/ 当除数和被除数都整形时,就是整除. 当浮点数和整数放到一起运算时,C语言会将整数转换成浮点数,然后进行浮点数的运算. #include<stdio.h> int main( ...