10.3 NOIP模拟赛 DP + 最小生成树 + 容斥
来源:互联网 发布:手机三维绘图软件 编辑:程序博客网 时间:2024/05/22 13:14
Mine
考虑dp[i][0/1][0/1], 表示第i位当前有雷(1), 无雷(0), 以及下一位有雷或者无雷. 转移见代码注释.
#include<stdio.h>#include<cstring>using namespace std;const int mod = 1e9 + 7;const int maxn = 1000005;char s[maxn];int f[maxn][2][2], ans;int main(){ freopen("mine.in", "r", stdin); freopen("mine.out", "w", stdout); scanf("%s", s); int len = strlen(s); if(s[0] == '2') {puts("0"); return 0;} if(s[0] == '0') f[0][0][0] = 1; if(s[0] == '1') f[0][0][1] = 1; if(s[0] == '*') f[0][1][0] = f[0][1][1] = 1; if(s[0] == '?') f[0][0][0] = f[0][0][1] = f[0][1][0] = f[0][1][1] = 1; for(int i = 1; i < len; ++i){ if(s[i] == '0') f[i][0][0] = f[i - 1][0][0]; //旁边都不能有雷 if(s[i] == '1'){ f[i][0][1] = f[i - 1][0][0]; //雷在右边 f[i][0][0] = f[i - 1][1][0]; //雷在左边 } if(s[i] == '2') f[i][0][1] = f[i - 1][1][0]; //两边都有, 只有一种转移 if(s[i] == '*') f[i][1][0] = f[i][1][1] = (f[i - 1][0][1] + f[i - 1][1][1]) % mod; if(s[i] == '?'){ f[i][0][0] = f[i][0][1] = (f[i - 1][1][0] + f[i - 1][0][0]) % mod; f[i][1][0] = f[i][1][1] = (f[i - 1][1][1] + f[i - 1][0][1]) % mod; } } ans = (f[len - 1][0][0] + f[len - 1][1][0]) % mod; printf("%d\n", ans);}
Water
这道题简直神题…好吧是我最小生成树的性质了解的太少了. 这道题说是在下雨但是相当于就是矩形外面有无限的水量涌进来, 最后不再进水后整个矩形最终的形态就是答案.
一开始以为对于某个点的答案就取四个方向的min值与自己的差就可以了, 后来才发现明明这个点可以存在于一个盆地的中央, 盆地边缘不一定在四周. 这个点还可以存在于高原的盆地, 盆地的盆地, 地势多样…
但是不难发现, 对于某一个点的答案, 因为短板效应, 相当于就是矩形外面的水涌进来, 答案就是min(任意一条到这个点的路径的最大值) -这个点的高度(当然若为负就为0). 其实最大边权的最小值的路一定就叫作最小瓶颈路. 这个路一定在最小生成树上. 那么我们加入’矩形外’这个点, 每个点之间向四周建边(边权为两个点之间的较大值). 边界点就会与矩形外这个点连边. 做一遍最小生成树, 然后从矩形外这个点开始dfs,就求到了矩形外到每个点的最小瓶颈路.
最小瓶颈路在最小生成树其实很好证. 因为假设u, v的最小瓶颈路的最大值不在最小生成树上的话, 那么这个边权一定比最小生成树上的u, v之间的路径要小. 因为这个边不在最小生成树上所以连在这上面就一定成环, 因为之前说过小于最小生成树上的最大值要小, 现在又构成了环, 所以这个最小瓶颈路的最大值去替换它. 与最小生成树的定义相悖. 所以一定在最小生成树上. 反正可得.
#include<stdio.h>#include<algorithm>using namespace std;const int maxn = 400005;int h[maxn], a[maxn], fa[maxn], mx[maxn], tot, n, m, num;struct edge{int u, nxt, v, w;}e[maxn], c[maxn];int find(int x) {return (fa[x] == x) ? x : fa[x] = find(fa[x]);}inline void add(int u, int v, int w){ e[++num].v = v, e[num].w = w, e[num].nxt = h[u], h[u] = num; e[++num].v = u, e[num].w = w, e[num].nxt = h[v], h[v] = num;}inline void adde(int u, int v, int w){ c[++num].u = u, c[num].v = v, c[num].w = w;}inline bool cmp(edge x, edge y){ return x.w < y.w;}inline void Kruskal(){ sort(c + 1, c + num + 1, cmp); for(int i = 0; i <= n * m; ++i) fa[i] = i; for(int i = 1; i <= num; ++i){ int x = find(c[i].u), y = find(c[i].v); if(x != y){ ++tot; fa[x] = y; add(c[i].u, c[i].v, c[i].w); if(tot == n * m) break; } } num = 0;}void dfs(int u, int fa){ for(int i = h[u]; i; i = e[i].nxt){ int v = e[i].v; if(v == fa) continue; mx[v] = max(mx[u], e[i].w); dfs(v, u); }}int main(){ freopen("water.in", "r", stdin); freopen("water.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &a[(i - 1) * m + j]); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j){ int now = (i - 1) * m + j; int fir = (j == 1) ? 0 : (i - 1) * m + j - 1; int sec = (j == n) ? 0 : (i - 1) * m + j + 1; int thi = (i == 1) ? 0 : (i - 2) * m + j; int fou = (i == n) ? 0 : i * m + j; adde(now, fir, max(a[now], a[fir])), adde(now, sec, max(a[now], a[sec])); adde(now, thi, max(a[now], a[thi])), adde(now, fou, max(a[now], a[fou])); } Kruskal(); dfs(0, 0); for(int i = 1; i <= n; ++i, puts("")) for(int j = 1; j <= m; ++j) printf("%d ", max(mx[(i - 1) * m + j] - a[(i - 1) * m + j], 0)); return 0;}/*3 34 4 02 1 33 3 -1*/
Gcd
给出n个数, 一开始都没被选.每次改变一个数的状态, 问当前所有数互质的无序对有多少对.
n <= 200000
直接上容斥原理. 比如当前加入x, 那么与x互质说明与x的质因数也互质. 将x质因数分解后, 设得到2, 3, 5, 7, 与x互质的数根据容斥原理可得就是 所有数 - 与2不互质的数(2的倍数)……+与2 * 3不互质的数……. 系数就是莫比乌斯函数.
将每个数因子分解就能维护上述 与2不互质的数…等.
o( n根号n)
#include<stdio.h>typedef long long dnt;const int maxm = 500005;bool mark[maxm]; dnt ans;int mu[maxm], pr[maxm], cnt[maxm], tot;inline const int read(){ register int x = 0; register char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x;}int a[maxm], c[maxm], n, m, num;inline void sieve(){ for(int i = 2; i <= maxm; ++i){ if(!mark[i]) pr[++tot] = i, mu[i] = 1; for(int j = 1; j <= tot && pr[j] * i <= maxm; ++j){ mark[pr[j] * i] = true; if((i % pr[j]) == 0){ mu[i * pr[j]] = 0; break; } else mu[i * pr[j]] = -mu[i]; } }}inline dnt query(int x){ dnt ret = cnt[x] * mu[x]; for(int i = 2; i * i <= x; ++i) if(!(x % i)){ if(i * i == x) ret += cnt[i] * mu[i]; else ret += cnt[i] * mu[i] + cnt[x / i] * mu[x / i]; } return ret;}inline void modify(int x, int delta){ cnt[x] += delta; num += delta; for(int i = 2; i * i <= x; ++i) if(!(x % i)){ if(i * i == x) cnt[i] += delta; else cnt[i] += delta, cnt[x / i] += delta; }}int main(){ freopen("gcd.in", "r", stdin); freopen("gcd.out", "w", stdout); sieve();int x; n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= m; ++i){ x = read(); c[x] ^= 1; if(c[x]) ans += num - query(a[x]), modify(a[x], +1); else modify(a[x], -1), ans -= num - query(a[x]); printf("%I64d\n", ans); }}
这两天考试状态不是很好, 发现主要问题是想的时间太多, 总是不敢动手. 稍微有一点没想对就始终不动手. 这就导致虽然代码能力还不错, 但是给的时间很少, 有的时候没想出来一道题就耽误很多时间, 写暴力也很仓促. 所以决定以后一道题20分钟内想不出来必须写暴力(如果会写的话), 不能太纠结. 刚开始看题的时间缩减为10min.
还有对于普通算法, 还不够精. 要少王偏难怪钻, 多多挖掘基础算法的性质, 多做模型转化的题目.
- 10.3 NOIP模拟赛 DP + 最小生成树 + 容斥
- [NOIP模拟][最小生成树]Roads
- NOIP模拟 图【最小生成树】
- NOIP 模拟题 friendly [最小生成树] [ST在线] [hash]
- 【NOIP 模拟题】最小生成树(Tarjan求桥)
- [NOIP模拟题][LIS][同余最短路][DP][矩阵快速幂][容斥原理]
- NOIP 模拟题 C17 [容斥原理]
- 10.11 NOIP模拟赛 DP + 线段树 + DP + 单调队列
- NOIP模拟题 [模拟][DP][线段树]
- #NOIP模拟赛#押韵rhyme(TRI树 + Dp)
- 10.4 NOIP模拟赛 线段树+DP+Trie
- NOIP模拟赛 数论专题 扩展欧几里得 + 组合数 + 容斥原理
- NOIP模拟题 [LIS][建图][递推][容斥]
- [NOIP模拟][容斥原理][快速幂]Heal
- [noip模拟赛]祖先(dp)
- [noip模拟赛]二进制(dp)
- [noip模拟赛]敲砖块(dp)
- #NOIP模拟赛#排列问题(DP)
- 树链剖分 模板
- kubelet 源码分析:Garbage Collect
- 64位WIN7下虚拟机安装winxp
- 1. Two Sum——LeetCode OJ
- Sublime text 3搭建Python开发环境
- 10.3 NOIP模拟赛 DP + 最小生成树 + 容斥
- 【C++】实现双向循环链表
- leecode 169. Majority Element(C语言,快速排序,堆排序,各类排序算法复杂度比较)22
- 基于TensorFlow实现Skip-Gram模型
- [反演] 2017 计蒜之道 复赛 A. 阿里云秘钥池
- URAL 1009|URAL 1012|URAL 1013|K-based Numbers|高精度|动态规划
- 用construct 2来做一个射击小游戏吧ヾ(o´∀`o)ノ
- 51Nod 1085背包问题(dp)
- poj 3177 Redundant Paths 边-双连通分量