Cqoi2017试题泛做

Day1

4813: [Cqoi2017]小Q的棋盘

树形背包DP。

 1 #include <cstdio>
 2
 3 #define maxn 110
 4 #define R register
 5 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
 6 struct Edge {
 7     Edge *next;
 8     int to;
 9 } *last[maxn], e[maxn << 1], *ecnt = e;
10 inline void link(R int a, R int b)
11 {
12     *++ecnt = (Edge) {last[a], b}; last[a] = ecnt;
13     *++ecnt = (Edge) {last[b], a}; last[b] = ecnt;
14 }
15 int f1[maxn][maxn], f2[maxn][maxn], m;
16 bool vis[maxn];
17 void dfs(R int x)
18 {
19     vis[x] = 1;
20     for (R int i = 0; i <= m; ++i) f1[x][i] = f2[x][i] = 1;
21     for (R Edge *iter = last[x]; iter; iter = iter -> next)
22         if (!vis[iter -> to])
23         {
24             dfs(iter -> to);
25             for (R int j = m; j; --j)
26                 for (R int k = 0; k < j; ++k)
27                 {
28                     cmax(f1[x][j], f2[x][j - k - 1] + f1[iter -> to][k]);
29                     k != j - 1 ? cmax(f1[x][j], f1[x][j - k - 2] + f2[iter -> to][k]) : 0;
30                 }
31             for (R int j = m; j >= 2; --j)
32                 for (R int k = 0; k < j - 1; ++k)
33                     cmax(f2[x][j], f2[x][j - k - 2] + f2[iter -> to][k]);
34         }
35 }
36 int main()
37 {
38     R int n; scanf("%d%d", &n, &m);
39     for (R int i = 1; i < n; ++i) {R int a, b; scanf("%d%d", &a, &b); link(a, b);}
40     dfs(0);
41     R int ans = 1;
42     for (R int i = 1; i <= m; ++i) cmax(ans, f1[0][i]), cmax(ans, f2[0][i]);
43     printf("%d\n", ans);
44     return 0;
45 }

D1T1

4814: [Cqoi2017]小Q的草稿

暂时还没做。marked。

4815: [Cqoi2017]小Q的表格

做完发现自己推式子和推结论的能力不足。这题有一个结论是只和对角线上的元素的权值有关,并且f[a,b]可以写成k*a*b的形式(这个结论我也是网上看的,但是我向BZOJ要的数据里这个条件并不满足,如果直接将题目给你的x/a/b得到的不会是一个整数,而把x/a/b改成模意义下x*a^(-1)*b^(-1)居然就能过了)。然后推出来是∑f[d]*∑∑(i*j*[gcd(i,j)==d]),然后还有一个结论是

∑i*[gcd(i,n)==1]=phi(n)*n/2。如果知道这两个结论应该剩下就只剩套路了(?)。设g[n] = ∑∑(i*j*[gcd(i,j)==1], 1<=i,j<=n),答案变成求∑f[d]*g[k/d]。然后k/d是根号分段的,根号枚举一下然后动态地求前缀和。前缀和这里用分块来实现根号修改O1查询。总的复杂度O(n+m√n)。

 1 #include <cstdio>
 2 #include <cmath>
 3
 4 #define R register
 5 #define maxn 4000010
 6 #define maxs 2333
 7 typedef long long ll;
 8 const int mod = 1e9 + 7;
 9 int pr[maxn], prcnt, phi[maxn], g[maxn], f[maxn];
10 int sum[maxn], ssum[maxs];
11 bool vis[maxn];
12 inline int qpow(R int base, R int power)
13 {
14     R int ret = 1;
15     for (; power; power >>= 1, base = 1ll * base * base % mod)
16         power & 1 ? ret = 1ll * ret * base % mod : 0;
17     return ret;
18 }
19 int gcd(R int a, R int b)
20 {
21     return !b ? a : gcd(b, a % b);
22 }
23 int main()
24 {
25     R int m, n; scanf("%d%d", &m, &n);
26     phi[1] = 1; g[1] = 1; f[1] = 1;
27     for (R int i = 2; i <= n; ++i)
28     {
29         if (!vis[i]) pr[++prcnt] = i, phi[i] = i - 1;
30         g[i] = (g[i - 1] + 1ll * i * i % mod * phi[i]) % mod;
31         f[i] = 1ll * i * i % mod;
32         for (R int j = 1; j <= prcnt && 1ll * pr[j] * i <= n; ++j)
33         {
34             vis[i * pr[j]] = 1;
35             if (i % pr[j] == 0)
36             {
37                 phi[i * pr[j]] = phi[i] * pr[j];
38                 break;
39             }
40             else phi[i * pr[j]] = phi[i] * phi[pr[j]];
41         }
42     }
43     R int size = sqrt(n), tot = n / size + 1;
44 //    printf("\nsize%d\n", size);
45     for (R int i = 1; i <= n; ++i)
46         if (i % size == 0) ssum[i / size] = (ssum[i / size - 1] + sum[i - 1]) % mod, sum[i] = f[i];
47         else sum[i] = (sum[i - 1] + f[i]) % mod;
48 //    for (R int i = 1; i <= n; ++i) printf("%d ", sum[i]); puts("");
49     for (; m; --m)
50     {
51         R int a, b, k, d; R ll x;
52         scanf("%d%d%lld%d", &a, &b, &x, &k);
53 //        if (x % a != 0 || x % b != 0) puts("WA"), printf("%lld %d %d %d\n", x, a, b, m);
54         x %= mod;
55 //        printf("kk %lld\n", kk);
56         f[d = gcd(a, b)] = 1ll * x * qpow(1ll * a * b % mod, mod - 2) % mod * d % mod * d % mod;
57         R int spos = d / size + 1;
58         for (R int i = d; i < spos * size; ++i) sum[i] = ((i % size == 0 ? 0 : sum[i - 1]) + f[i]) % mod;
59         for (R int i = spos; i <= tot; ++i) ssum[i] = (ssum[i - 1] + sum[i * size - 1]) % mod;
60 //        for (R int i = 1; i <= n; ++i) printf("%d ", sum[i]); puts("");
61         R int ans = 0;
62         #define query(x) (sum[(x)] + ssum[(x) / size])
63         for (R int i = 1, j; i <= k; i = j + 1)
64         {
65             j = k / (k / i);
66             ans = (ans + 1ll * (query(j) % mod - query(i - 1) % mod + mod) % mod * g[k / i]) % mod;
67         }
68         printf("%d\n", ans);
69     }
70     return 0;
71 }

D1T3

Day2

4822: [Cqoi2017]老C的任务

挺裸的二维数点问题。扫描线+树状数组简单维护即可。(将一个询问拆成几个前缀询问加加减减的形式)

 1 #include <cstdio>
 2 #include <algorithm>
 3
 4 #define R register
 5 #define lowbit(_x) ((_x) & -(_x))
 6 #define maxn 100010
 7 struct Event {
 8     int type, id, x, l, r;
 9     inline bool operator < (const Event &that) const {return x < that.x || (x == that.x && type < that.type);}
10 } p[maxn << 2];
11 int hash[maxn << 2], hcnt, pcnt;
12 typedef long long ll;
13 ll b[maxn << 2], ans[maxn];
14 inline void add(R int pos, R int val)
15 {
16     for (; pos <= hcnt; pos += lowbit(pos)) b[pos] += val;
17 }
18 inline ll query(R int pos)
19 {
20     R ll ret = 0;
21     for (; pos; pos -= lowbit(pos)) ret += b[pos];
22     return ret;
23 }
24 int main()
25 {
26     R int n, m, pcnt = 0; scanf("%d%d", &n, &m);
27     for (R int i = 1; i <= n; ++i)
28     {
29         R int x, y, pi; scanf("%d%d%d", &x, &y, &pi);
30         hash[++hcnt] = y;
31         p[++pcnt] = (Event) {1, 0, x, y, pi};
32     }
33     for (R int i = 1; i <= m; ++i)
34     {
35         R int x_1, y_1, x_2, y_2; scanf("%d%d%d%d", &x_1, &y_1, &x_2, &y_2);
36         hash[++hcnt] = y_1; hash[++hcnt] = y_2;
37         p[++pcnt] = (Event) {2, i, x_1 - 1, y_1, y_2};
38         p[++pcnt] = (Event) {3, i, x_2, y_1, y_2};
39     }
40     std::sort(hash + 1, hash + hcnt + 1);
41     hcnt = std::unique(hash + 1, hash + hcnt + 1) - hash - 1;
42     std::sort(p + 1, p + pcnt + 1);
43     for (R int i = 1; i <= pcnt; ++i)
44     {
45         p[i].l = std::lower_bound(hash + 1, hash + hcnt + 1, p[i].l) - hash;
46         if (p[i].type == 1)
47         {
48             add(p[i].l, p[i].r);
49         }
50         else
51         {
52             p[i].r = std::lower_bound(hash + 1, hash + hcnt + 1, p[i].r) - hash;
53             if (p[i].type == 2) ans[p[i].id] -= query(p[i].r) - query(p[i].l - 1);
54             else ans[p[i].id] += query(p[i].r) - query(p[i].l - 1);
55         }
56     }
57     for (R int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
58     return 0;
59 }

D2T1

4823: [Cqoi2017]老C的方块

刚开始我连构图都没想到。后来看了题解完构图还是构错了。

将格子染成如上图所示的四种颜色,然后每一种方块都可以表示成0-1-2-3的形式。然后构建分层图,一条从s到t的路径表示的就是一个弃疗的方块,所以跑一个最小割即可。然后我一开始好像染色还染错了,注意一下染色的顺序(一定得都是0-1-2-3的形式),如果染不清楚的话可能会有奇怪的错误。还有,10w的网络流到底是怎么跑过去的,我不是很能理解啊。。。

  1 #include <cstdio>
  2 #include <map>
  3 #include <algorithm>
  4 #include <cstring>
  5
  6 #define R register
  7 #define P std::pair<int, int>
  8 #define maxn 200010
  9 #define inf 0x7fffffff
 10 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
 11 std::map<P, int> id;
 12 int x[maxn], y[maxn], w[maxn];
 13 struct Edge {
 14     Edge *next, *rev;
 15     int to, cap;
 16 } *last[maxn], *cur[maxn], e[maxn * 10], *ecnt = e;
 17 inline void link(R int a, R int b, R int w)
 18 {
 19 //  printf("%d %d %d\n", a, b, w);
 20     *++ecnt = (Edge) {last[a], ecnt + 1, b, w}; last[a] = ecnt;
 21     *++ecnt = (Edge) {last[b], ecnt - 1, a, 0}; last[b] = ecnt;
 22 }
 23 int dep[maxn], q[maxn], s, t, ans;
 24 inline bool bfs()
 25 {
 26     memset(dep, -1, (t + 1) << 2);
 27     dep[q[1] = t] = 0; R int head = 0, tail = 1;
 28     while (head < tail)
 29     {
 30         R int now = q[++head];
 31         for (R Edge *iter = last[now]; iter; iter = iter -> next)
 32             if (iter -> rev -> cap && dep[iter -> to] == -1)
 33                 dep[q[++tail] = iter -> to] = dep[now] + 1;
 34     }
 35     return dep[s] != -1;
 36 }
 37 int dfs(R int x, R int f)
 38 {
 39     if (x == t) return f;
 40     R int used = 0;
 41     for (R Edge* &iter = cur[x]; iter; iter = iter -> next)
 42         if (iter -> cap && dep[iter -> to] + 1 == dep[x])
 43         {
 44             R int v = dfs(iter -> to, dmin(f - used, iter -> cap));
 45             iter -> cap -= v;
 46             iter -> rev -> cap += v;
 47             used += v;
 48             if (used == f) return f;
 49         }
 50     return used;
 51 }
 52 void dinic()
 53 {
 54     while (bfs())
 55     {
 56         memcpy(cur, last, sizeof cur);
 57         ans += dfs(s, inf);
 58     }
 59 }
 60 void build(R int _x, R int _y, R int i)
 61 {
 62     R P next;
 63     next = std::make_pair(_x, _y);
 64     if (id[next]) link(id[next] << 1 | 1, i << 1, inf);
 65 }
 66 int main()
 67 {
 68     R int c, r, n; scanf("%d%d%d", &c, &r, &n);
 69     for (R int i = 1; i <= n; ++i)
 70     {
 71         scanf("%d%d%d", &x[i], &y[i], &w[i]);
 72         R P pos = std::make_pair(x[i], y[i]);
 73         id[pos] = i;
 74     }
 75     s = 0; t = n * 2 + 2;
 76     for (R int i = 1; i <= n; ++i)
 77     {
 78         R int col = y[i] & 1 ? x[i] % 4 : (x[i] % 4) ^ 1;
 79 //      printf("x %d y %d col %d\n", x[i], y[i], col);
 80         link(i << 1, i << 1 | 1, w[i]);
 81         if (col == 0)
 82         {
 83             link(s, i << 1, inf);
 84         }
 85         else if (col == 1)
 86         {
 87             build(x[i], y[i] - 1, i);
 88             build(x[i], y[i] + 1, i);
 89             build(x[i] + (y[i] & 1 ? -1 : 1), y[i], i);
 90         }
 91         else if (col == 2)
 92         {
 93             build(x[i] + (y[i] & 1 ? -1 : 1), y[i], i);
 94         }
 95         else if (col == 3)
 96         {
 97             build(x[i], y[i] - 1, i);
 98             build(x[i], y[i] + 1, i);
 99             build(x[i] + (y[i] & 1 ? -1 : 1), y[i], i);
100             link(i << 1 | 1, t, inf);
101         }
102     }
103     dinic();
104     printf("%d\n", ans);
105     return 0;
106 }

D2T2

4824: [Cqoi2017]老C的键盘

还没做。marked。

时间: 2024-10-31 04:07:44

Cqoi2017试题泛做的相关文章

Shoi2017试题泛做

一口气做完六个省的省选(误) Day1 [Shoi2017]期末考试 枚举最大的天数,然后代价贪心地O(1)计算. 1 #include <cstdio> 2 #include <algorithm> 3 4 #define R register 5 typedef long long ll; 6 #define maxn 100010 7 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) 8 #define cmin(_a,

Hnoi2017试题泛做

Day1 4825: [Hnoi2017]单旋 注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序. 所以我们可以离线地把这棵树的中序遍历求出来.然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态. 接着我们发现将最大.最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1.于是我们就只要支持单点修改.区间加.单点查询的数据结构即可.树状数组就好了. 然后树的形态维护的时候大力判断一下就好啦. 1 #include <cstdio> 2

「美团 CodeM 资格赛」试题泛做

LibreOJ真是吼啊! 数码 推个式子,把枚举因数转为枚举倍数.然后就发现它是根号分段的.然后每一段算一下就好了. 1 #include <cstdio> 2 #include <cstring> 3 4 #define R register 5 typedef long long ll; 6 struct Data { 7 ll num[10]; 8 inline void clear() 9 { 10 memset(num, 0, 10 << 3); 11 } 1

历年NOIP水题泛做

快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时候最小点击次数 递推的话对于上升的情况只做一次,后面几次在后面再做.. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace st

codeforce 泛做

1A - Theatre Square 题意:有一个规模为n*m的剧院,用a*a的地板来铺满,问需要多少块木板. 思路:水题. 1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cstdio> 7 #include<vector> 8 #define

# 清北冬令营真题泛做

清北冬令营真题泛做 前言 这段时间为了准备冬令营把清北冬令营真题都做了一下.更个博回顾一下(免得你们老说我咕咕咕). 先写良心PKU的题再写THU的题, 主要是THU的题和PKU比起来真的毒瘤好多...... PKUWC2018 [PKUWC2018]Minimax 一个比较显然的暴力是归并排序,每次直接前后缀计算答案即可. 为啥不用线段树合并代替归并排序呢? 暴力线段树合并,合并的过程中顺便算一下即可,由于权值区间不交所以复杂度一个\(log\). [PKUWC2018]Slay the Sp

HAOI2015 泛做

T1 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益.问受益最大值是多少.N,K<=2000 这个树形dp不是很好想...因为贡献十分混乱... 题解十分神奇...我们记f[i][j]为i的子树有j个黑点的最大权值. 注意直接dp十分蛋疼,这个权值指的是,这个子树内部的贡献,以及i与父亲之间的边对答案的贡献(比如这条边对黑点对距离和的贡

[DynamicProgramming]动态规划题目泛做

Educational Codeforces Round 12 F 大意: 求n(n<=1011)以内恰好有4个因数的数的个数 分析: 首先一个数恰好有4个因数,说明它质因数分解之后是两个质数的乘积或是一个质数的三次方,对于后一种情况我们直接n1/3就能算出来,关键在于计算n以内有多少个数是两个素数的乘积. 设n=p1?p2,则必然有p1<n?√,p2>n?√,我们枚举p1,那么问题就在于np1 内有多少个素数. 这一点我们用dp来解决. 记pj为第j个素数,dp[n][j]为[1,n]

背包DP泛做

DP太弱了,要多做. 结果做了一堆傻逼题... 洛谷P2639: 01背包 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define max(a, b) (a < b ? b : a) const int MAXN = 500; using namespace std; inline int read() { int x = 0, w = 1; c