Liu_runda聚聚的馈赠(
Problem A: 周
防自闭题?
这道题让我整个考试都很愉悦(
搜就完事了

1 #include <bits/stdc++.h>
2
3 int n;
4 int a[20], b[20], c[20], d[20];
5 long long ans;
6
7 void dfs(int day, long long oi, long long whk) {
8 if (day == n + 1) {
9 ans = std::max(ans, oi * whk);
10 return;
11 }
12 long long x, y;
13 x = oi - b[day] < 0 ? 0 : oi - b[day], y = whk + a[day];
14 dfs(day + 1, x, y);
15 x = oi + c[day], y = whk - d[day] < 0 ? 0 : whk - d[day];
16 dfs(day + 1, x, y);
17 }
18
19 signed main() {
20 scanf("%d", &n);
21 for (int i = 1; i <= n; i++)
22 scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
23 dfs(1, 0, 0);
24 printf("%lld\n", ans);
25 return 0;
26 }
Problem B: 任
题目保证黑点之间只有一条简单路径,显然相邻黑点连边就是一颗树。
求森林有几棵树:总点数-边数。
二维前缀和ning干:记点的前缀和、行上边的前缀和、列上边的前缀和、边的前缀和。
加加减减乱搞一下就有了。

1 #include <bits/stdc++.h>
2
3 int n, m, q;
4 int color[2005][2005], sum[2005][2005], edge[2005][2005];
5 int row[2005][2005], col[2005][2005];
6
7 signed main() {
8 scanf("%d%d%d", &n, &m, &q);
9 for (int i = 1; i <= n; i++) {
10 for (int j = 1; j <= m; j++) {
11 scanf("%1d", &color[i][j]);
12 row[i][j] = (color[i][j-1] + color[i][j]) == 2;
13 col[i][j] = (color[i-1][j] + color[i][j]) == 2;
14 sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];
15 edge[i][j] = edge[i-1][j] + edge[i][j-1] - edge[i-1][j-1];
16 sum[i][j] += color[i][j];
17 edge[i][j] += row[i][j] + col[i][j];
18 }
19 }
20 for (int i = 1; i <= n; i++)
21 for (int j = 1; j <= m; j++)
22 row[i][j] += row[i][j-1];
23 for (int j = 1; j <= m; j++)
24 for (int i = 1; i <= n; i++)
25 col[i][j] += col[i-1][j];
26 for (int i = 1; i <= q; i++) {
27 int x_1, x_2, y_1, y_2;
28 scanf("%d%d%d%d", &x_1, &y_1, &x_2, &y_2);
29 int point = sum[x_2][y_2] - sum[x_1-1][y_2] -
30 sum[x_2][y_1-1] + sum[x_1-1][y_1-1];
31 int edg = edge[x_2][y_2] - edge[x_1][y_2] - edge[x_2][y_1] + edge[x_1][y_1];
32 int waste = row[x_1][y_2] + col[x_2][y_1] - row[x_1][y_1] - col[x_1][y_1];
33 printf("%d\n", point - edg - waste);
34 }
35 return 0;
36 }
Problem C: 飞
2h做一道题((
首先能看出来是求逆序对数。
恶意的出题人把size卡到32M Orz
本题专属奇妙性质:x在每一段是一个等差数列,而且题目保证x互不相同。
首先他有一个固定的形式:$x_{i+1} = x_i + a$。
我们就钦定它小于P,大于再说(
我们再钦定和x_i组成的逆序对数为m,之前已经组成了k个等差数列。
由于$x_{i+1}$小于P,之前的每个等差数列都必定存在一个数大于$x_i$小于$x_{i+1}$,因此每个等差数列会少一对逆序对,与$x_{i+1}$组成的逆序对数为m-k。
递推总要有个起点8?根据等差数列的首项确定等差数列。因此树状数组还是要开的,不过在a上开就行,这样空间就够用了。
对拍的时候发现一个坑:可能第一个等差数列起点就比$x_i$大了,特判掉就吼了(

1 #include <bits/stdc++.h>
2
3 const int N = 1e5 + 3;
4 int n, x_1, a, mod, now, chaos, sairai;
5 long long ans = 0;
6
7 struct BIT {
8 int tr[N];
9 void add(int x) {
10 ++x;
11 for (; x < N; x += x & -x) ++tr[x];
12 }
13 int ask(int x) {
14 int ret = 0;
15 ++x;
16 for (; x; x -= x & -x) ret += tr[x];
17 return ret;
18 }
19 } bit;
20
21 signed main() {
22 scanf("%d%d%d%d", &n, &x_1, &a, &mod);
23 now = x_1;
24 for (int i = 1; i <= n; ++i) {
25 if (now < a) {
26 chaos = i - bit.ask(now) - 1;
27 ans += chaos;
28 bit.add(now);
29 } else {
30 chaos -= sairai;
31 if (x_1 > now) ++chaos;
32 ans += chaos;
33 }
34 now += a;
35 if (now >= mod) {
36 now -= mod;
37 ++sairai;
38 }
39 }
40 printf("%lld\n", ans);
41 return 0;
42 }
