各种OJ刷题记录6.27-7.6
来源:互联网 发布:大漠驼铃 php 编辑:程序博客网 时间:2024/05/17 01:00
各种OJ刷题记录6.27-7.6
6175. 「美团 CodeM 初赛 Round B」黑白树
之前一道题的增强版…
考虑所有
但对于
http://blog.csdn.net/mengxiang000000/article/details/73718867
考虑先用一边dfs记录子树中覆盖当前节点最浅到哪里,计为
没太看懂神犇们的高端写法…只好大力树剖+树状数组维护了。
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;struct node { int to, next;} edge[MAXN];int head[MAXN], top = 0;inline void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }int siz[MAXN], id[MAXN], ind[MAXN], id_in_ds = 0;int c[MAXN];int n;int ki[MAXN];int depth[MAXN], fa[MAXN][20];int low_dep[MAXN];int dfn[MAXN], dfn_top = 0;inline int lowbit(int i){ return i&(-i); }void modify(int i, int dt){ for (; i <= n; i += lowbit(i)) c[i] += dt;}void cover(int i, int j){ modify(i, 1), modify(j+1, -1); }int dat(int i){ int ans = 0; for (; i; i -= lowbit(i)) ans += c[i]; return ans;}int kth_ans(int nd, int k){ if (k >= depth[nd]) k = depth[nd]; for (register int i = 0; i < 20; i++) if (k&(1<<i)) nd = fa[nd][i]; return nd;}void dfs_init(int nd){ siz[nd] = 1; for (register int i = 1; i < 20; i++) fa[nd][i] = fa[fa[nd][i-1]][i-1]; low_dep[nd] = kth_ans(nd, ki[nd]-1); for (int i = head[nd]; i; i = edge[i].next) { depth[edge[i].to] = depth[nd]+1; dfs_init(edge[i].to), siz[nd] += siz[edge[i].to]; if (depth[low_dep[edge[i].to]] < depth[low_dep[nd]]) low_dep[nd] = low_dep[edge[i].to]; } dfn[++dfn_top] = nd;}inline bool cmp(int a, int b){ return depth[a] > depth[b]; }void dfs_build(int nd, int from){ id[nd] = ++id_in_ds, ind[nd] = from; int hev = -1; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (hev == -1 || siz[to] > siz[hev]) hev = to; } if (hev == -1) return; dfs_build(hev, from); for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to != hev) dfs_build(to, to); }}void cover_point(int nd, int pt){ while (depth[ind[nd]] > depth[pt]) { cover(id[ind[nd]], id[nd]); nd = fa[ind[nd]][0]; } if (depth[nd] >= depth[pt]) cover(id[pt], id[nd]);}int main(){ scanf("%d", &n); for (int i = 2; i <= n; i++) scanf("%d", &fa[i][0]), push(fa[i][0], i); for (int i = 1; i <= n; i++) scanf("%d", &ki[i]); dfs_init(1); dfs_build(1, 1); int cnt = 0; for (int i = 1; i <= n; i++) { int pt = dfn[i]; if (dat(id[pt]) != 0) continue; int anc = low_dep[pt]; cover_point(pt, anc), cnt++; } printf("%d\n", cnt); return 0;}
loj#112. 三维偏序
填坑…
不知道为什么印象特别深刻去年一次NOIP模拟赛建出二维数点模型,然后Too Naive,并不会做…一直向转化成逆序对…学习了一个偏序那套理论才知道Too Simple..
经典题,一维排序,二维归并,三维树状数组。
注意check一下相同的情况。
#include <bits/stdc++.h>using namespace std;inline int read(){ int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}const int MAXN = 100005;struct pt { int x, y, z, id;} pts[MAXN], tmp[MAXN];int n, k;inline bool cmp_x(const pt &a, const pt &b){ return a.x < b.x; }inline bool cmp_y(const pt &a, const pt &b){ return a.y < b.y; }int ans[MAXN];int c[MAXN*2];inline int lowbit(int i){ return i&(-i); }void modify(int i, int dt){ for (; i <= k; i += lowbit(i)) c[i] += dt;}int sum(int i){ int ans = 0; for (; i; i -= lowbit(i)) ans += c[i]; return ans;}void solve(int l, int r, int L, int R){ if (l >= r) return; L = pts[l].x, R = pts[r].x; if (L == R) { sort(pts+l, pts+r+1, cmp_y); int lp = l, rp = l; while (lp <= r) { while (rp+1 <= r && pts[rp+1].y == pts[lp].y) rp++; for (int i = lp; i <= rp; i++) modify(pts[i].z, 1); for (int i = lp; i <= rp; i++) ans[pts[i].id] += sum(pts[i].z)-1; lp = rp = rp+1; } for (int i = l; i <= r; i++) modify(pts[i].z, -1); return; } int MID = (L+R)>>1; int lp = l, rp = r; for (int i = l; i <= r; i++) { if (pts[i].x <= MID) tmp[lp++] = pts[i]; else tmp[rp--] = pts[i]; } int mid = lp-1; for (int i = l; i <= r; i++) pts[i] = tmp[i]; solve(l, mid, L, MID), solve(mid+1, r, MID+1, R); lp = l, rp = mid+1; int tmp_l = l; while (lp <= mid && rp <= r) { if (pts[lp].y <= pts[rp].y) { modify(pts[lp].z, 1); tmp[tmp_l++] = pts[lp++]; } else { ans[pts[rp].id] += sum(pts[rp].z); tmp[tmp_l++] = pts[rp++]; } } while (lp <= mid) { modify(pts[lp].z, 1); tmp[tmp_l++] = pts[lp++]; } while (rp <= r) { ans[pts[rp].id] += sum(pts[rp].z); tmp[tmp_l++] = pts[rp++]; } for (int i = l; i <= mid; i++) modify(pts[i].z, -1); for (int i = l; i <= r; i++) pts[i] = tmp[i];}int d[MAXN];int main(){ scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) pts[i].x = read(), pts[i].y = read(), pts[i].z = read(), pts[i].id = i; sort(pts+1, pts+n+1, cmp_x); solve(1, n, 1, k); for (int i = 1; i <= n; i++) d[ans[i]]++; for (int i = 0; i < n; i++) printf("%d\n", d[i]); return 0;}
NOIP2016 天天爱跑步
填一下这个坑….
考虑向上的路径
也就是
#include <bits/stdc++.h>#include <ext/rope>using namespace __gnu_cxx;using namespace std;const int MAXN = 300005;struct node { int to, next;} edge[MAXN*2];int head[MAXN], top = 0;inline void push(int i, int j){ edge[++top] = (node){j, head[i]}, head[i] = top; }int depth[MAXN], W[MAXN];int u[MAXN*2], v[MAXN*2], id[MAXN*2];int n, m;int lca[MAXN], vis[MAXN];int fa[MAXN], father[MAXN], ans[MAXN];inline int findf(int nd){ return fa[nd]?fa[nd]=findf(fa[nd]):nd; }inline int read(){ int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}vector<int> pt[MAXN];struct tag { int dat; int tp;};vector<tag> tag_up[MAXN], tag_down[MAXN];void dfs_init(int nd, int f){ vis[nd] = 1, father[nd] = f; for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i) if (vis[v[*i]]) { lca[id[*i]] = findf(v[*i]); } for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to == f) continue; depth[to] = depth[nd]+1, dfs_init(to, nd); } fa[nd] = f;}void put_tag(){ for (int i = 1; i <= m; i++) { int c = lca[i], s = u[i], t = v[i]; if (c == t) { tag_up[s].push_back((tag){depth[s], 1}); tag_up[father[c]].push_back((tag){depth[s], -1}); } else if (c == s) { tag_down[t].push_back((tag){-depth[s], 1}); tag_down[father[c]].push_back((tag){-depth[s], -1}); } else { tag_up[s].push_back((tag){depth[s], 1}); tag_up[father[c]].push_back((tag){depth[s], -1}); int beg = depth[s]-depth[c]; tag_down[t].push_back((tag){beg-depth[c], 1}); tag_down[c].push_back((tag){beg-depth[c], -1}); } }}int dfn[MAXN], dfn_top = 0, out[MAXN];struct my_array { rope<int> *arr[MAXN]; int range_l, range_r, lev; void build() { arr[0] = new rope<int>; lev = 0; for (int i = range_l; i <= range_r; i++) arr[0]->push_back(0); } inline void new_lev() { ++lev, arr[lev] = new rope<int>(*arr[lev-1]); } inline void add_pos(int pos, int dt) { pos = pos-range_l; int dat = arr[lev]->at(pos)+dt; arr[lev]->replace(pos, dat); } inline int segment_sum(int l, int r, int pos) { return arr[r]->at(pos-range_l)-arr[l-1]->at(pos-range_l); }} arr_up, arr_down;void dfs_travel(int nd){ dfn[nd] = ++dfn_top; arr_up.new_lev(), arr_down.new_lev(); for (register vector<tag>::iterator i = tag_up[nd].begin(); i != tag_up[nd].end(); ++i) arr_up.add_pos(i->dat, i->tp); for (register vector<tag>::iterator i = tag_down[nd].begin(); i != tag_down[nd].end(); ++i) arr_down.add_pos(i->dat, i->tp); for (register int i = head[nd]; i; i = edge[i].next) if (edge[i].to != father[nd]) dfs_travel(edge[i].to); out[nd] = dfn_top;}int main(){ freopen("runninga.in", "r", stdin); freopen("runninga.out", "w", stdout); int size = 128 << 20; char *p = (char*)malloc(size) + size; __asm__("movl %0, %%esp\n" :: "r"(p)); n = read(), m = read(); for (register int i = 1; i < n; i++) { int x = read(), y = read(); push(x, y), push(y, x); } for (register int i = 1; i <= n; i++) W[i] = read(); for (register int i = 1; i <= m; i++) { u[i] = read(), v[i] = read(); u[m+i] = v[i], v[m+i] = u[i], id[m+i] = id[i] = i; pt[u[i]].push_back(i), pt[v[i]].push_back(i+m); } dfs_init(1, 0); put_tag(); arr_up.range_l = 0, arr_up.range_r = 2*n+1, arr_down.range_l = -n-1, arr_down.range_r = n+1; arr_up.build(), arr_down.build(); dfs_travel(1); for (register int i = 1; i <= n; i++) { ans[i] += arr_up.segment_sum(dfn[i], out[i], depth[i]+W[i]); ans[i] += arr_down.segment_sum(dfn[i], out[i], W[i]-depth[i]); } for (register int i = 1; i <= n; i++) printf("%d ", ans[i]); puts(""); return 0;}
然而这题就是典型“会的越多得分越低”型题目…这个可持久化维护的特别鸡肋。由于答案具有可减性,我们在dfs的过程中维护一个数组,进入时记录一下答案,退出时记录一下,差值就是所求了…
#include <bits/stdc++.h>#include <ext/rope>using namespace __gnu_cxx;using namespace std;const int MAXN = 300005;struct node { int to, next;} edge[MAXN*2];int head[MAXN], top = 0;inline void push(int i, int j){ edge[++top] = (node){j, head[i]}, head[i] = top; }int depth[MAXN], W[MAXN];int u[MAXN*2], v[MAXN*2], id[MAXN*2];int n, m;int lca[MAXN], vis[MAXN];int fa[MAXN], father[MAXN], ans[MAXN];inline int findf(int nd){ return fa[nd]?fa[nd]=findf(fa[nd]):nd; }inline int read(){ int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}vector<int> pt[MAXN];struct tag { int dat; int tp;};vector<tag> tag_up[MAXN], tag_down[MAXN];void dfs_init(int nd, int f){ vis[nd] = 1, father[nd] = f; for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i) if (vis[v[*i]]) { //cerr << *i << " " << id[*i] << " " << v[*i] << endl; lca[id[*i]] = findf(v[*i]); } for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to == f) continue; depth[to] = depth[nd]+1, dfs_init(to, nd); } fa[nd] = f;}void put_tag(){ for (int i = 1; i <= m; i++) { int c = lca[i], s = u[i], t = v[i]; // cerr << "LCA(" << s << "," << t << ") = " << c << endl; if (c == t) { tag_up[s].push_back((tag){depth[s], 1}); tag_up[father[c]].push_back((tag){depth[s], -1}); } else if (c == s) { tag_down[t].push_back((tag){-depth[s], 1}); tag_down[father[c]].push_back((tag){-depth[s], -1}); } else { tag_up[s].push_back((tag){depth[s], 1}); tag_up[father[c]].push_back((tag){depth[s], -1}); int beg = depth[s]-depth[c]; tag_down[t].push_back((tag){beg-depth[c], 1}); tag_down[c].push_back((tag){beg-depth[c], -1}); } }}int arr_up[MAXN*4], arr_down[MAXN*4], beg = 600000;void dfs_travel(int nd){ int pre = arr_up[depth[nd]+W[nd]+beg] + arr_down[W[nd]-depth[nd]+beg]; for (register int i = head[nd]; i; i = edge[i].next) if (edge[i].to != father[nd]) dfs_travel(edge[i].to); for (register vector<tag>::iterator i = tag_up[nd].begin(); i != tag_up[nd].end(); ++i) arr_up[i->dat+beg] += i->tp; for (register vector<tag>::iterator i = tag_down[nd].begin(); i != tag_down[nd].end(); ++i) arr_down[i->dat+beg] += i->tp; ans[nd] = arr_up[depth[nd]+W[nd]+beg] + arr_down[W[nd]-depth[nd]+beg]-pre;}int main(){ n = read(), m = read(); for (register int i = 1; i < n; i++) { int x = read(), y = read(); push(x, y), push(y, x); } for (register int i = 1; i <= n; i++) W[i] = read(); for (register int i = 1; i <= m; i++) { u[i] = read(), v[i] = read(); u[m+i] = v[i], v[m+i] = u[i], id[m+i] = id[i] = i; pt[u[i]].push_back(i), pt[v[i]].push_back(i+m); } dfs_init(1, 0); put_tag(); dfs_travel(1); for (register int i = 1; i <= n; i++) printf("%d ", ans[i]); puts(""); return 0;}
NOIP2015 运输计划
继续填古代坑计划…
当时用SPFA水了25…
现在看来很水啊..二分后随便树剖就行了。也可以树上差分搞。
#include <bits/stdc++.h>using namespace std;const int MAXN = 300005;struct node { int to, next, dis;} edge[MAXN*2];int head[MAXN], top = 0;inline void push(int i, int j, int d){ edge[++top] = (node) {j, head[i], d}, head[i] = top; }int fa[MAXN];inline int findf(int a){ return fa[a]?fa[a] = findf(fa[a]):a; }int u[MAXN*2], v[MAXN*2], id[MAXN*2], lca[MAXN], vis[MAXN], father[MAXN];int dis[MAXN];int n, m;vector<int> pt[MAXN];int depth[MAXN], len[MAXN];inline int read(){ int a = 0, c; do c = getchar(); while (!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}void dfs_init(int nd, int f){ vis[nd] = 1, father[nd] = f; for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i) if (vis[v[*i]]) lca[id[*i]] = findf(v[*i]); for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to == f) continue; depth[to] = depth[nd]+1, len[to] = len[nd]+edge[i].dis; dfs_init(to, nd); } fa[nd] = f;}int tag[MAXN], max_able = 0;void dfs_collect(int nd){ for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to == father[nd]) continue; dfs_collect(to), tag[nd] += tag[to]; }}bool check(int ans){ memset(tag, 0, sizeof tag); int max_val = 0, cnt = 0; max_able = 0; for (int i = 1; i <= m; i++) if (dis[i] > ans) { max_val = max(max_val, dis[i]); cnt++; // cerr << u[i] << " " << v[i] << " " << lca[i] << endl; tag[u[i]]++, tag[v[i]]++, tag[father[lca[i]]]--, tag[lca[i]]--; } if (cnt == 0) return 1; //cerr << cnt << endl; dfs_collect(1); for (int i = 1; i <= n; i++) { if (tag[i] != cnt) continue; //cerr << tag[i] << endl; for (int j = head[i]; j; j = edge[j].next) { int to = edge[j].to; // if (to == father[i]) continue; if (tag[to] == cnt) max_able = max(max_able, edge[j].dis); } } //cerr << max_val << " " << max_able << " " << ans << endl; return max_val-max_able <= ans; }int main(){ //freopen("transport.in", "r", stdin); //freopen("transport.out", "w", stdout); n = read(), m = read(); for (int i = 1; i < n; i++) { int l = read(), r = read(), d = read(); push(l, r, d), push(r, l, d); } for (int i = 1; i <= m; i++) { u[i] = read(), v[i] = read(); v[i+m] = u[i], u[i+m] = v[i], id[i] = id[i+m] = i; pt[u[i]].push_back(i), pt[v[i]].push_back(i+m); } dfs_init(1, 0); for (int i = 1; i <= m; i++) dis[i] = len[u[i]]+len[v[i]]-len[lca[i]]*2; int l = 0, r = 300000ll*1000, mid; while (l <= r) { mid = (l+r)>>1; if (check(mid)) r = mid-1; else l = mid+1; } printf("%d\n", r+1); return 0;}
loj#6066. 「2017 山东一轮集训 Day3」第二题
我SX….原来括号序列就是dfs序啊..
二分答案
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;struct node { int to, next;} edge[MAXN];int head[MAXN], top = 0;void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }int hash_dat[MAXN*2], dfn_top = 0;vector<pair<int, int> > forbidden[MAXN];int fa[MAXN][20], n;int dfn_in[MAXN], dfn_out[MAXN];typedef unsigned long long ull;ull hash_tab[MAXN*2], bs = 19260817, power[MAXN*2];int height[MAXN];// --- hash ---void hash_init(){ power[0] = 1; for (int i = 1; i <= n*2; i++) power[i] = power[i-1]*bs; for (int i = 1; i <= n*2; i++) hash_tab[i] = hash_tab[i-1]*bs+hash_dat[i];}ull hash_val(int l, int r){ return hash_tab[r]-hash_tab[l-1]*power[r-l+1]; }// --- hash ---int kth_anc(int nd, int k){ for (int i = 0; i < 20; i++) if (k&(1<<i)) nd = fa[nd][i]; return nd;}void dfs_init(int nd){ height[nd] = 0; ++dfn_top, hash_dat[dfn_top] = 1; dfn_in[nd] = dfn_top; for (int i = 1; i < 20; i++) fa[nd][i] = fa[fa[nd][i-1]][i-1]; for (int i = head[nd]; i; i = edge[i].next) { fa[edge[i].to][0] = nd, dfs_init(edge[i].to); height[nd] = max(height[nd], height[edge[i].to]+1); } ++dfn_top, hash_dat[dfn_top] = 2; dfn_out[nd] = dfn_top;}set<ull> st;bool calc(int k){ for (int i = 1; i <= n; i++) forbidden[i].clear(); st.clear(); for (int i = 1; i <= n; i++) { int nd = kth_anc(i, k+1); forbidden[nd].push_back(make_pair(dfn_in[i], dfn_out[i])); } for (int i = 1; i <= n; i++) { sort(forbidden[i].begin(), forbidden[i].end()); forbidden[i].push_back(make_pair(dfn_out[i]+1, dfn_out[i]+1)); } for (int i = 1; i <= n; i++) { if (height[i] < k) continue; ull hash_v = 0; int l = dfn_in[i]; for (int j = 0, sz = forbidden[i].size(); j < sz; j++) { int r = forbidden[i][j].first-1; if (l <= r) hash_v = hash_v*power[r-l+1]+hash_val(l, r); l = forbidden[i][j].second+1; } if (st.count(hash_v)) return 1; st.insert(hash_v); } return 0;}inline int read(){ int a = 0, c; do c = getchar(); while (!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}int rd[MAXN], rt;int main(){ n = read(); for (int i = 1; i <= n; i++) { int x, v; x = read(); for (int j = 1; j <= x; j++) v = read(), push(i, v), rd[v]++; } for (int i = 1; i <= n; i++) if (rd[i] == 0) { rt = i; break; } dfs_init(rt), hash_init(); int l = 0, r = n, mid; while (l <= r) { mid = (l+r)>>1; if (calc(mid)) l = mid+1; else r = mid-1; } printf("%d\n", l-1); return 0;}
loj #6173. Samjia和矩阵
这个命题思路在哪里见过….当时是kmp,现在用SAM就好了。
考虑枚举矩形的高度
人话就是,把一列看成一个字符。
然后就可以用广义后缀自动机大法了。由于字符集太大,需要hash+map<ull>
。
ps : std貌似是后缀数组,复杂度少一个
#include <bits/stdc++.h>using namespace std;typedef unsigned long long ull;int n, m;char A[115][115];const int MAXN = 30005;const ull bas = 19260817;struct SAM { map<ull,int> chl[MAXN]; int fa[MAXN], maxl[MAXN], top, root; void clear() { top = root = 1, maxl[1] = 0; } int push(int nd, ull dat) { int p = nd, np = ++top; maxl[np] = maxl[p]+1, chl[np].clear(); while (p && !chl[p][dat]) chl[p][dat] = np, p = fa[p]; if (!p) fa[np] = root; else { int q = chl[p][dat]; if (maxl[q] == maxl[p]+1) fa[np] = q; else { int nq = ++top; chl[nq] = chl[q], maxl[nq] = maxl[p]+1; fa[nq] = fa[q], fa[q] = fa[np] = nq; while (p && chl[p][dat] == q) chl[p][dat] = nq, p = fa[p]; } } return np; }} sam_main;struct trie { map<ull, int> tree[MAXN]; int top, root; trie() { top = root = 1; } void clear() { for (int i = 1; i <= top; i++) tree[i].clear(); top = root = 1; } void push(vector<ull> &str) { int nd = root; for (auto i : str) { if (!tree[nd].count(i)) tree[nd][i] = ++top; nd = tree[nd][i]; } }} trie_main;queue<int> que;int st[MAXN];void bfs_build_sam(){ sam_main.clear(); que.push(trie_main.root); st[trie_main.root] = sam_main.root; while (!que.empty()) { int nd = que.front(); que.pop(); for (auto i : trie_main.tree[nd]) { st[i.second] = sam_main.push(st[nd], i.first); que.push(i.second); } }}int solve(){ bfs_build_sam(); int ans = 0; for (int i = 2; i <= sam_main.top; i++) ans += sam_main.maxl[i]-sam_main.maxl[sam_main.fa[i]]; return ans;}ull hash_val[120][120]; // i, j 第i列前j项哈希ull power[120];inline ull hash_seg(int i, int l, int r){ return hash_val[i][r]-hash_val[i][l-1]*power[r-l+1]; }int main(){ scanf("%d%d", &n, &m); power[0] = 1; for (int i = 1; i <= n; i++) power[i] = power[i-1]*bas; for (int i = 1; i <= n; i++) scanf("%s", A[i]+1); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) hash_val[i][j] = hash_val[i][j-1]*bas+A[j][i]-'A'+1; } vector<ull> vec; int ans = 0; for (int i = 1; i <= n; i++) { trie_main.clear(); for (int j = 1; j+i-1 <= n; j++) { vec.clear(); for (int k = 1; k <= m; k++) vec.push_back(hash_seg(k, j, j+i-1)); trie_main.push(vec); } ans += solve(); } cout << ans << endl; return 0;}
loj#2098. 「CQOI2015」多项式
看不懂神犇五行代码系列qwq…
考虑展开右边级数第
然后就py直接做了…
import mathdef choose(n, k): ans = 1 for i in range(k): ans = ans*(n-i) for i in range(1, k+1): ans = ans/i return ansn = int(raw_input())t = int(raw_input())m = int(raw_input())def mul(a, b): c = {} for i in range(2): for j in range(2): c[i, j] = 0 for k in range(2): c[i, j] = (c[i, j]+a[i, k]*b[k, j])%3389 return cdef power(a, n): ans = {(0,0):1, (1,1):1, (1, 0):0, (0,1):0} for i in range(10000): if (((n>>i)&1) != 0): ans = mul(ans, a) a = mul(a, a) return ansdef get_A(n): c = {} c[0, 0], c[0, 1], c[1, 0], c[1, 1] = 1234, 5678, 0, 1 c = power(c, n) return (c[0, 0]+c[0, 1])%3389b = {}b[0] = get_A(n)for i in range(1, 6): tmp, flag, tt = n-i, 1, t b[i] = get_A(n-i) for j in range(1, i+1): b[i] = b[i]+b[i-j]*choose(tmp+j, j)*t**j*flag flag, tt = -flag, tt*t # print(b[i])print(b[n-m])
「NOI2016」优秀的拆分
补题计划continue…
首先考场是肯定写85-95的…后面的性价比不高..
正解其实也(看过题解后)比较简单。考虑求
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;typedef unsigned long long ull;char str[MAXN];int n, T;ull hash_tab[MAXN], bas = 31;long long hash_tab2[MAXN], bas2 = 97, mod = 1e9+7;ull power[MAXN];long long power2[MAXN];void hash_init(){ for (register int i = 1; i <= n+n; i++) hash_tab[i] = hash_tab[i-1]*bas+str[i]-'a'+1; for (register int i = 1; i <= n+n; i++) hash_tab2[i] = (hash_tab2[i-1]*bas2%mod+str[i]-'a'+1)%mod;}inline ull hash_val1(int l, int r){ return l <= r ? hash_tab[r]-hash_tab[l-1]*power[r-l+1] : 0; }inline ull hash_val2(int l, int r){ return l <= r ? ((hash_tab2[r]-hash_tab2[l-1]*power2[r-l+1]%mod)%mod+mod)%mod : 0; }int tag_after[MAXN], tag_bef[MAXN];int pos[MAXN], top = 0;int max_len_lr(int a, int b, int upp){ register int l = 0, r = upp, mid; while (l <= r) { mid = (l+r)>>1; if (hash_val1(a, a+mid-1) == hash_val1(b, b+mid-1) && hash_val2(a, a+mid-1) == hash_val2(b, b+mid-1)) l = mid+1; else r = mid-1; } return l-1;}int max_len_rl(int a, int b, int upp){ register int l = 0, r = upp, mid; while (l <= r) { mid = (l+r)>>1; if (hash_val1(a-mid+1, a) == hash_val1(b-mid+1, b) && hash_val2(a-mid+1, a) == hash_val2(b-mid+1, b)) l = mid+1; else r = mid-1; } return l-1;}int main(){ scanf("%d", &T); while (T--) { scanf("%s", str+1); memset(tag_bef, 0, sizeof tag_bef); memset(tag_after, 0, sizeof tag_after); n = strlen(str+1); power[0] = power2[0] = 1; for (register int i = 1; i <= n; i++) power[i] = power[i-1]*bas; for (register int i = 1; i <= n; i++) power2[i] = power2[i-1]*bas2%mod; for (register int i = n+1; i <= n+n; i++) str[i] = int('z')+1; hash_init(); for (register int i = 1; i <= n; i++) { top = 0; do { ++top, pos[top] = pos[top-1]+i; } while (pos[top] < n); register int a, b, lr, rl; for (register int j = 1; j < top; j++) { a = pos[j], b = pos[j+1]; lr = max_len_lr(a, b, i), rl = max_len_rl(a, b, i); if (lr+rl-1 < i) continue; tag_after[b+i-rl]++, tag_after[b+lr]--; tag_bef[a-(i-lr)+1]--, tag_bef[a-rl+1]++; } } for (register int i = 1; i <= n+n; i++) tag_after[i] += tag_after[i-1], tag_bef[i] += tag_bef[i-1]; long long ans = 0; for (register int i = 1; i <= n; i++) ans += (long long)tag_after[i]*tag_bef[i+1]; printf("%lld\n", ans); } return 0;}
「NOI2016」循环之美
好神啊….感觉在考场上最多推出84…
首先打个表发现所求其实就是:
然后交换求和顺序并莫比乌斯大力算,得出:
设
由辗转相除法可以得出
这样就可以大力
剩下的比较有构造性…设
考虑
由
大功告成…
#include <bits/stdc++.h>using namespace std;const int MAXK = 2005, MAXN = 1000005;const int MOD = 1000007, bas = 2333;int cnt = 0;struct hash_table { long long tab[MOD]; int n[MOD], k[MOD]; inline int hash_val(int n, int k) { return ((long long)n*bas%MOD+k)%MOD; } inline long long val(int __n, int __k) { int val = hash_val(__n, __k); while (n[val] != __n || k[val] != __k) (val += 1) %= MOD; return tab[val]; } inline void insert(int __n, int __k, long long dat) { int val = hash_val(__n, __k); while (k[val] != 0 || n[val] != 0) val++; n[val] = __n, k[val] = __k, tab[val] = dat; } inline bool count(int __n, int __k) { int val = hash_val(__n, __k); while (n[val] != __n || k[val] != __k) { if (n[val] == 0 && k[val] == 0) return 0; val++; } return 1; }};inline int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); }int prime[MAXN], not_prime[MAXN], mu[MAXN], top = 0;int M[MAXN];int n, m, k;int p[MAXK], q[MAXK]; // 拿出的第一个素因子; 剩余int f[MAXK];void get_prime(int n){ mu[1] = 1, not_prime[1] = 1; for (int i = 2; i <= n; i++) { if (!not_prime[i]) prime[++top] = i, mu[i] = -1; for (int j = 1; j <= top && i*prime[j] <= n; j++) { not_prime[i*prime[j]] = 1; if (i%prime[j] == 0) { mu[i*prime[j]] = 0; break; } mu[i*prime[j]] = -mu[i]; } } for (int i = 1; i <= n; i++) M[i] = M[i-1]+mu[i];}hash_table hash_M;long long get_M(int N){ if (N < MAXN) return M[N]; if (hash_M.count(N, 0)) return hash_M.val(N, 0); long long ans = 1; int last; for (int i = 2; i <= N; i = last+1) { last = N/(N/i); ans -= (last-i+1)*get_M(N/i); } hash_M.insert(N, 0, ans); return ans;}hash_table hash_s;long long get_G(int n, int k){ // cerr << n << " " << k << endl; if (n == 0) return 0; if (k == 1) return get_M(n); if (hash_s.count(n, k)) return cnt++, hash_s.val(n, k); long long tmp = get_G(n, q[k])+get_G(n/p[k], p[k]*q[k]); hash_s.insert(n, k, tmp); return tmp;}void init_pq(){ for (int i = 2; i <= k; i++) { if (!not_prime[i]) p[i] = i, q[i] = 1; else { int fac, pp = 1; for (int j = 1; j <= top; j++) if (i%prime[j] == 0) { fac = prime[j]; break; } while (i%(pp*fac) == 0) pp *= fac; p[i] = fac, q[i] = i/pp; } }}void init_f(){ f[0] = 0; for (int i = 1; i <= k; i++) f[i] = f[i-1]+(gcd(i, k) == 1);}inline int get_F(int n){ return n/k*f[k]+f[n%k]; }int main(){ cin >> n >> m >> k; get_prime(MAXN-1); init_pq(); init_f(); int last; long long ans = 0; for (register int i = 1; i <= n && i <= m; i = last+1) { last = min(min(n/(n/i), m/(m/i)), n); ans += (get_G(last, k)-get_G(i-1, k))*(n/i)*get_F(m/i); } cout << ans << endl; return 0;}
「NOI2016」区间
可能是NOI2016唯一一道水题吧……
#include <bits/stdc++.h>using namespace std;const int MAXN = 500005;struct segm { int l, r, len; friend bool operator < (const segm &a, const segm &b) { return a.len < b.len; }} seg[MAXN];int n, m;int dx[MAXN*2], dx_top = 0;void dx_init(){ for (int i = 1; i <= n; i++) dx[++dx_top] = seg[i].l, dx[++dx_top] = seg[i].r; sort(dx+1, dx+dx_top+1); dx_top = unique(dx+1, dx+dx_top+1)-dx-1; for (int i = 1; i <= n; i++) { seg[i].l = lower_bound(dx+1, dx+dx_top+1, seg[i].l)-dx; seg[i].r = lower_bound(dx+1, dx+dx_top+1, seg[i].r)-dx; }}int max_val[MAXN*4], lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], tag[MAXN*4];int root = 0, top = 0;inline void pdw(int nd){ max_val[nd] += tag[nd]; if (lc[nd]) tag[lc[nd]] += tag[nd], tag[rc[nd]] += tag[nd]; tag[nd] = 0;}inline void update(int nd){ max_val[nd] = max(max_val[lc[nd]], max_val[rc[nd]]); }void build(int &nd, int opl, int opr){ nd = ++top, l[nd] = opl, r[nd] = opr; if (opl < opr) build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);}void modify(int nd, int opl, int opr, int dt){ pdw(nd); if (l[nd] == opl && r[nd] == opr) tag[nd] += dt; else { int mid = (l[nd] + r[nd]) >> 1; if (opr <= mid) modify(lc[nd], opl, opr, dt); else if (opl > mid) modify(rc[nd], opl, opr, dt); else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt); pdw(lc[nd]), pdw(rc[nd]), update(nd); }}int query(int nd, int opl, int opr){ pdw(nd); if (l[nd] == opl && r[nd] == opr) return max_val[nd]; else { int mid = (l[nd] + r[nd]) >> 1; if (opr <= mid) return query(lc[nd], opl, opr); else if (opl > mid) return query(rc[nd], opl, opr); else return max(query(lc[nd], opl, mid), query(rc[nd], mid+1, opr)); }}inline int read(){ int a = 0, c; do c = getchar(); while (!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}int main(){ n = read(), m = read(); for (int i = 1; i <= n; i++) { seg[i].l = read(); seg[i].r = read(); seg[i].len = seg[i].r-seg[i].l; } sort(seg+1, seg+n+1); dx_init(); build(root, 1, dx_top); int ans = INT_MAX; int l = 1, r = 0; while (r < n) { while (r < n && query(root, 1, dx_top) < m) ++r, modify(root, seg[r].l, seg[r].r, 1); if (query(root, 1, dx_top) >= m) ans = min(ans, seg[r].len-seg[l].len); while (l <= n && query(root, 1, dx_top) >= m) { if (query(root, 1, dx_top) >= m) ans = min(ans, seg[r].len-seg[l].len); modify(root, seg[l].l, seg[l].r, -1); l++; } if (query(root, 1, dx_top) >= m) ans = min(ans, seg[r].len-seg[l].len); } if (ans == INT_MAX) puts("-1"); else printf("%d\n", ans); return 0;}
NOI2015 寿司餐厅
每个数大于
#include <bits/stdc++.h>using namespace std;const int MAXN = 505;int n;long long P;int prime[] = {2, 3, 5, 7, 11, 13, 17, 19};long long dp[2][1<<8|1][1<<8|1];long long p[2][2][1<<8|1][1<<8|1];vector<int> kind[MAXN];int main(){ scanf("%d%lld", &n, &P); for (int i = 2; i <= n; i++) { int S = 0, num = i; for (int j = 0; j < 8; j++) if (num%prime[j] == 0) { S |= 1<<j; while (num%prime[j] == 0) num /= prime[j]; } if (num == 1) kind[n+1].push_back(S); else kind[num].push_back(S); } int now = 0, nxt = 1; dp[now][0][0] = 1; for (register int i = 0; i <= n; i++) { int nw = 0, nx = 1; if (kind[i].empty()) continue; memcpy(p[0][nw], dp[now], sizeof dp[now]); memset(p[0][nx], 0, sizeof p[0][nx]); memcpy(p[1][nw], dp[now], sizeof dp[now]); memset(p[1][nx], 0, sizeof p[1][nx]); for (register vector<int>::iterator l = kind[i].begin(); l != kind[i].end(); ++l) { //cerr << i << " " << *l << endl; for (register int j = 0; j < 1<<8; j++) for (register int k = 0; k < 1<<8; k++) { (p[0][nx][j][k] += p[0][nw][j][k]) %= P; (p[1][nx][j][k] += p[1][nw][j][k]) %= P; (p[0][nx][j|(*l)][k] += p[0][nw][j][k]) %= P; (p[1][nx][j][k|(*l)] += p[1][nw][j][k]) %= P; } memset(p[0][nw], 0, sizeof p[0][nw]); memset(p[1][nw], 0, sizeof p[1][nw]); swap(nw, nx); } for (register int j = 0; j < 1<<8; j++) for (register int k = 0; k < 1<<8; k++) dp[now][j][k] = (p[0][nw][j][k]+p[1][nw][j][k]-dp[now][j][k])%P; } for (register int i = 1; i <= kind[n+1].size(); i++) { int S = kind[n+1][i-1]; for (register int j = 0; j < 1<<8; j++) for (register int k = 0; k < 1<<8; k++) { long long val = dp[now][j][k]; (dp[nxt][j][k] += val) %= P; (dp[nxt][j][k|S] += val) %= P; (dp[nxt][j|S][k] += val) %= P; } memset(dp[now], 0, sizeof dp[now]); swap(now, nxt); } long long ans = 0; for (register int j = 0; j < 1<<8; j++) { for (register int k = 0; k < 1<<8; k++) { if ((j&k) == 0) (ans += dp[now][j][k]) %= P; //cerr << dp[now][j][k] << " "; } //cerr << endl; } printf("%lld\n", (ans+P)%P); return 0;}
「NOI2015」荷马史诗
真…哈夫曼编码裸题
#include <bits/stdc++.h>using namespace std;const int MAXN = 100050;long long w[MAXN];int n, k;long long tot_len = 0;struct pt { long long val; int lev; friend bool operator < (const pt &a, const pt &b) { return a.val == b.val ? a.lev > b.lev : a.val > b.val; }};priority_queue<pt> heap; int main(){ scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) scanf("%lld", &w[i]); while ((n-1)%(k-1) != 0) w[++n] = 0; for (int i = 1; i <= n; i++) heap.push((pt){w[i], 0}); while (heap.size() > 1) { long long val = 0; int lev = 0; for (int i = 1; i <= k; i++) { pt a = heap.top(); heap.pop(); val += a.val, lev = max(lev, a.lev); } tot_len += val; heap.push((pt){val, lev+1}); } cout << tot_len << endl << heap.top().lev << endl; return 0;}
4545: DQS的trie
LCT维护广义后缀自动机Right集合大小…………………..
太TM难写了啊…
「不过貌似用splay维护dfs序要好写一点…什么时候尝试一个」
#include <bits/stdc++.h>using namespace std;const int MAXN = 300005;struct link_cut_trees { int chl[MAXN][2], fa[MAXN], rev[MAXN]; int tag[MAXN], dat[MAXN]; int stk[MAXN], top; bool is_rt(int x) { return chl[fa[x]][0] != x && chl[fa[x]][1] != x;} inline void pdw(int nd) { if (chl[nd][0]) tag[chl[nd][0]] += tag[nd], rev[chl[nd][0]] ^= rev[nd]; if (chl[nd][1]) tag[chl[nd][1]] += tag[nd], rev[chl[nd][1]] ^= rev[nd]; if (rev[nd]) swap(chl[nd][0], chl[nd][1]); dat[nd] += tag[nd]; rev[nd] = 0, tag[nd] = 0; } void zig(int nd) { int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p; int son = chl[nd][tp^1]; if (son) fa[son] = p; if (!is_rt(p)) chl[g][tg] = nd; fa[nd] = g, fa[p] = nd, chl[nd][tp^1] = p, chl[p][tp] = son; } void splay(int nd) { stk[top = 1] = nd; for (int i = nd; !is_rt(i); i = fa[i]) stk[++top] = fa[i]; while (top) pdw(stk[top--]); while (!is_rt(nd)) { int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p; if (is_rt(p)) { zig(nd); break; } if (tp == tg) zig(p), zig(nd); else zig(nd), zig(nd); } } void access(int x) { for (int y = 0; x; x = fa[y = x]) splay(x), chl[x][1] = y; } void make_rt(int x) { access(x), splay(x), rev[x] ^= 1; } void link(int x, int y) // x --> y { fa[x] = y, access(y), splay(y), tag[y] += dat[x]; } void cut(int x) { access(x), splay(x), tag[chl[x][0]] -= dat[x]; fa[chl[x][0]] = 0, chl[x][0] = 0; } int get_dat(int x) { access(x), splay(x); return dat[x]; }} ;struct SAM { int chl[MAXN][3], fa[MAXN], maxl[MAXN], top, root; link_cut_trees LCT; long long ans; SAM() { top = root = 1, ans = 0; } int push(int nd, int x) { int p = nd, np = ++top; LCT.dat[np] = 1, maxl[np] = maxl[p]+1; while (p && !chl[p][x]) chl[p][x] = np, p = fa[p]; if (!p) fa[np] = root, ans += maxl[np]-maxl[fa[np]], LCT.link(np, root); else { int q = chl[p][x]; if (maxl[q] == maxl[p]+1) fa[np] = q, ans += maxl[np]-maxl[fa[np]], LCT.link(np, q); else { int nq = ++top; maxl[nq] = maxl[p]+1; memcpy(chl[nq], chl[q], sizeof chl[q]); fa[nq] = fa[q], LCT.link(nq, fa[nq]); ans += maxl[nq]-maxl[fa[nq]]; ans -= maxl[q]-maxl[fa[q]]; fa[q] = fa[np] = nq; ans += maxl[q]-maxl[fa[q]], ans += maxl[np]-maxl[fa[np]]; LCT.cut(q), LCT.cut(np), LCT.link(np, nq), LCT.link(q, nq); while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p]; } } return np; } int get_pt(int nd, const char *str) { if (*str == '\0') return nd; if (!chl[nd][*str-'a']) return -1; return get_pt(chl[nd][*str-'a'], str+1); } inline long long diff_substring() { return ans; } inline int match_times(const char *str) { int nd = get_pt(root, str); if (nd == -1) return 0; return LCT.get_dat(nd); }};struct trie { struct node { int to, next; char dis; } edge[MAXN*2]; int head[MAXN], top; inline void push(int i, int j, char c) { edge[++top] = (node){j, head[i], c}, head[i] = top; } int stat[MAXN], vis[MAXN]; int root; SAM autometa; queue<int> que; trie() { root = 1, stat[root] = 1, top = 0; } void dfs(int x) { vis[x] = 1; for (int i = head[x]; i; i = edge[i].next) { int to = edge[i].to, c = edge[i].dis-'a'; if (vis[to]) continue; stat[to] = autometa.push(stat[x], c); dfs(to); } } inline int match_times(const char *str) { return autometa.match_times(str); } inline long long diff_substring() { return autometa.diff_substring(); }} T;int n, m;int id;char str[MAXN];int main(){ scanf("%d%d", &id, &n); for (int i = 1; i < n; i++) { int u, v; char c; scanf("%d%d %c\n", &u, &v, &c); T.push(u, v, c), T.push(v, u, c); } T.dfs(1); scanf("%d", &m); for (int i = 1; i <= m; i++) { int opt, r, t; scanf("%d", &opt); if (opt == 1) { printf("%lld\n", T.diff_substring()); } else if (opt == 2) { scanf("%d%d", &r, &t), t--; while (t--) { int u, v; char c; scanf("%d%d %c\n", &u, &v, &c); T.push(u, v, c), T.push(v, u, c); } T.dfs(r); } else if (opt == 3) { scanf("%s", str); printf("%d\n", T.match_times(str)); } else throw; } return 0;}
- 各种OJ刷题记录6.27-7.6
- 各种OJ刷题记录5.31-6.8
- 各种OJ刷题记录6.9-6.15
- OJ平台刷题记录1
- oj简单题记录
- OI刷题记录
- OI刷题记录~
- leetcode刷题记录
- 刷题记录
- 6.22刷题记录
- 7.26-刷题记录
- hdu 刷题记录
- 面试刷题记录
- 每日刷题记录
- leetcode刷题记录
- hdu刷题记录
- LightOJ刷题记录
- leetcode刷题记录
- homestead注意事项
- Node JS实现简单网页服务器
- [Sklearn应用5] Feature Selection 特征选择(一) SelectFromModel
- Kotlin-23.内联函数(Inline Functions)
- 微店 Android 插件化实践
- 各种OJ刷题记录6.27-7.6
- Linux/Mac 交叉编译 Android 程序
- 机器学习实战--朴素贝叶斯
- 如何在一个Tomcat下部署两个应用
- eclipse如何设置点击页面找到侧边的目录
- 多线程
- java鬼混笔记:websocket java 多人聊天和一对一聊天
- udp程序设计
- codevs 3117 高精度练习之乘法