NOIP模拟测试20

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 }
A

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 }
B

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 }
C
posted @ 2019-08-17 19:18  Gekoo  阅读(...)  评论(...编辑  收藏