vijos训练之——星辰大海中闪烁的趣题
2017-03-05 21:22
357 查看
看到难度普遍7-9就感觉很劲…再加上doc出品,于是果断入坑。由于知识性内容还没有学完,只能慢慢刷了。
由于是回文串只要枚举前半段,然后瞎几把测试素数就好了。
顺便学习一波miller-rabin的二次探查。
复杂度O(n√Slgn),S为测试次数。
就是线段树维护总和,最大子段和,左起最大子段和,右起最大子段和。
复杂度O(nlgn)
最小割经典建图:
S→row
col→T
row→col,if there is something at (row,col)
正确性是显然的,复杂度O(跑得过)。
貌似用二分图匹配也可以?但我不会匈牙利那一套理论。
构造问题,由于有二叉树计数考虑用卡特兰数。然后瞎几把搞【雾】。
复杂度O(lgn)。因为卡特兰数是指数增长,其反函数是对数增长。
章节 1. 一些简单的练手题
1.1 捕风捉影
这sb题居然智障WA了两次….由于是回文串只要枚举前半段,然后瞎几把测试素数就好了。
顺便学习一波miller-rabin的二次探查。
复杂度O(n√Slgn),S为测试次数。
#include <bits/stdc++.h> using namespace std; long long power(long long a, long long n, long long mod) { if (n == 0) return 1%mod; long long p = power(a, n>>1, mod); p = p*p%mod; if (n&1) p = p*a%mod; return p; } bool miller_rabin(long long n) { if (n == 2) return 1; if (n < 2 || !(n&1)) return 0; int k; long long u; for (k=0, u=n-1; !(u&1); u>>=1, k++); for (int i = 1; i < 20; i++) { long long x = rand()%(n-2)+2, pre; if (x%n == 0) continue; x = power(x, u, n); pre = x; for (int j = 1; j <= k; j++) { x = x*x%n; if (x == 1 && pre != 1 && pre != n-1) return 0; pre = x; } if (x != 1) return 0; } return 1; } long long rev(long long a) { long long t = 0; while (a) t = (t+a%10)*10, a /= 10; return t/10; } long long ans[100005]; int top = 0; int main() { srand(time(0)); long long n, m; cin >> n >> m; if (5 >= n && 5 <= m) ans[++top] = 5; if (7 >= n && 7 <= m) ans[++top] = 7; int len = 1; for (long long i = 1; i <= 10000; i++) { long long l = i, r = rev(i); long long lk = l*power(10, len, LONG_LONG_MAX)+r; if (lk >= n && lk <= m && miller_rabin(lk)) ans[++top] = lk; for (int j = 0; j < 10; j++) { lk = l*power(10, len+1, LONG_LONG_MAX)+j*power(10, len, LONG_LONG_MAX)+r; if (lk >= n && lk <= m && miller_rabin(lk)) ans[++top] = lk; } if (i >= power(10, len, LONG_LONG_MAX)-1) len++; } sort(ans+1, ans+top+1); top = unique(ans+1, ans+top+1)-ans-1; for (int i = 1; i <= top; i++) printf("%lld\n", ans[i]); return 0; }
1.2 小白逛公园
以前写线段树查询从来都是直接返回答案…做了这题才发现可以返回一个完整的节点信息。就是线段树维护总和,最大子段和,左起最大子段和,右起最大子段和。
复杂度O(nlgn)
#include <bits/stdc++.h> using namespace std; const int MAXN = (1<<19)+2; struct node { int lsum, rsum, sum, subsum, l, r; node():l(0),r(0){} friend bool operator == (const node &a, const node &b) { return a.l == b.l; } } tree[MAXN*2]; int a[MAXN], n, m; #define nil tree[0] node link(const node &l, const node &r) { if (l == nil) return r; if (r == nil) return l; node nd; nd.sum = l.sum + r.sum; nd.lsum = max(l.lsum, l.sum+r.lsum); nd.rsum = max(r.rsum, r.sum+l.rsum); nd.subsum = max(l.subsum, max(r.subsum, l.rsum+r.lsum)); return nd; } void build(int nd, int l, int r) { if (l < r) { build(nd*2, l, (l+r)/2); build(nd*2+1, (l+r)/2+1, r); tree[nd] = link(tree[nd*2], tree[nd*2+1]); tree[nd].l = l, tree[nd].r = r; } else { tree[nd].l = tree[nd].r = l; tree[nd].sum = tree[nd].lsum = tree[nd].rsum = tree[nd].subsum = a[l]; } } void dfs(int nd, int tab = 0) { if (!tree[nd].l) return; for (int i = 1; i <= tab; i++) putchar(' '); //printf("[%d,%d] : %d,%d,%d,%d\n", tree[nd].l, tree[nd].r, tree[nd].lsum, tree[nd].rsum, tree[nd].subsum, tree[nd].sum); dfs(nd*2, tab+2); dfs(nd*2+1, tab+2); } void update(int nd, int pos, int dat) { if (tree[nd].l == tree[nd].r) { tree[nd].sum = tree[nd].lsum = tree[nd].rsum = tree[nd].subsum = dat; } else { int l = tree[nd].l, r = tree[nd].r; update((pos<=(l+r)/2)?nd*2:nd*2+1, pos, dat); tree[nd] = link(tree[nd*2], tree[nd*2+1]); tree[nd].l = l, tree[nd].r = r; } } node query(int nd, int l, int r) { if (l > r) return nil; if (tree[nd].l == l && tree[nd].r == r) return tree[nd]; node d = link(query(nd*2, l, min(r, tree[nd*2].r)), query(nd*2+1, max(l, tree[nd*2+1].l), r)); //printf("[%d,%d] %d %d->%d,%d,%d\n", tree[nd].l, tree[nd].r, l, r, d.subsum, d.lsum,d .rsum); return d; } int main() { scanf("%d%d", &n, &m); tree[0].l = 123231131; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); for (int i = 1; i <= m; i++) { int opt, opl, opr; scanf("%d%d%d", &opt, &opl, &opr); if (opt == 1) { if (opl > opr) swap(opl, opr); printf("%d\n",query(1, opl, opr).subsum); } else if (opt == 2) { update(1, opl, opr); } else dfs(1); } return 0; }
1.3 CoVH之柯南开锁
一开始以为是反转思考了好久,后来才发现只是按下去。最小割经典建图:
S→row
col→T
row→col,if there is something at (row,col)
正确性是显然的,复杂度O(跑得过)。
貌似用二分图匹配也可以?但我不会匈牙利那一套理论。
#include <bits/stdc++.h> using namespace std; const int MAXN = 50005, MAXM = 5000005; struct node { int to, next, f, neg; } edge[MAXM]; int head[MAXN], top = 0; void push(int i, int j, int k) { ++top, edge[top] = (node) {j, head[i], k, top+1}, head[i] = top; ++top, edge[top] = (node) {i, head[j], 0, top-1}, head[j] = top; } int vis[MAXN], bfstime = 0; int lev[MAXN], S = 50001, T = 50002; queue<int> que; bool bfs() { vis[S] = ++bfstime, lev[S] = 0, que.push(S); while (!que.empty()) { int tp = que.front(); que.pop(); for (int i = head[tp]; i; i = edge[i].next) { if (edge[i].f == 0 || vis[edge[i].to] == bfstime) continue; vis[edge[i].to] = bfstime, lev[edge[i].to] = lev[tp]+1, que.push(edge[i].to); } } return vis[T] == bfstime; } int dfs(int nd, int maxf = 233333333) { if (nd == T || !maxf) return maxf; int ans = 0, t; for (int i = head[nd]; i; i = edge[i].next) { if (edge[i].f == 0 || lev[edge[i].to] != lev[nd] + 1) continue; t = dfs(edge[i].to, min(maxf, edge[i].f)); ans += t, maxf -= t; edge[i].f -= t, edge[edge[i].neg].f += t; } if (maxf) lev[nd] = -1; return ans; } int dinic() { int ans = 0; while (bfs()) ans += dfs(S); return ans; } int n, m; char str[105]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) push(S, i, 1); for (int i = 1; i <= m; i++) push(n+i, T, 1); for (int i = 1; i <= n; i++) { scanf("%s", str+1); for (int j = 1; j <= m; j++) if (str[j] == '1') push(i, n+j, 1); } cout << dinic() << endl; return 0; }
章节 2. 轻松点它们很简单
2.1 cpc的逃离
变得难起来了…构造问题,由于有二叉树计数考虑用卡特兰数。然后瞎几把搞【雾】。
复杂度O(lgn)。因为卡特兰数是指数增长,其反函数是对数增长。
#include <bits/stdc++.h> using namespace std; // C : h(n)=h(n-1)*(4*n-2)/(n+1); long long h[20]; void work(int n, long long k, bool out_side = 1) // n个节点中编号为k的 { //cerr << endl << n << " " << k << endl; if (k*n == 0) return; if (!out_side) putchar('('); for (int i = 0; i < n; i++) { if (h[i]*h[n-i-1] < k) k -= h[i]*h[n-i-1]; else { work(i, (k-1)/h[n-i-1]+1, 0); putchar('X'); work(n-i-1, k%h[n-i-1]?k%h[n-i-1]:h[n-i-1], 0); break; } } if (!out_side) putchar(')'); } int main() { h[0] = 1; for (int i = 1; i < 20; i++) h[i] = h[i-1]*(4*i-2)/(i+1);//, printf("%lld\n", h[i]); long long x; while (scanf("%lld", &x), x != 0) { int i = 1; for (; x > h[i]; x -= h[i], i++); work(i, x); puts(""); } return 0; }
相关文章推荐
- 算法提高 我们的征途是星辰大海
- 双11迎来爆发,苏宁"智慧零售"的未来是星辰大海
- 重新制定了目标 这样才知道为啥活着 重新起航 星辰大海
- 星辰大海
- 重庆一中Vijos 【训练题】步步为零 P1428 题解
- 我们的征程是星辰大海,迈向不可知的彼岸
- 面向星辰大海,出发吧骚年!
- 我们是程序员,我们的征途是星辰大海
- Vijos P1881 闪烁的繁星
- 蓝桥杯 算法提高 我们的征途是星辰大海
- 算法提高 我们的征途是星辰大海
- 我们的征程是星辰大海
- Vijos训练计划 1-1 计数问题
- 产品化的EasyStack即是星辰大海
- 自适应网站前途星辰大海
- 技术人攻略访谈三十五-小猴机器人:征途路上,星辰大海
- 1881闪烁的繁星——线段树vijos
- Getting iOS Done 1.1从label开始,前面是星辰大海
- Vijos1881闪烁的繁星 [线段树]
- “双十一” 已经 7 岁了,但阿里们的征途依旧还有星辰大海