bzoj刷题记录4.10-4.14
来源:互联网 发布:淘宝网上批发市场 编辑:程序博客网 时间:2024/06/05 00:32
bzoj刷题记录4.10-4.14
bzoj1093: [ZJOI2007]最大半联通子图
仍然缩点。缩完点之后每个半联通子图就相当于一条带权链(权值是一个scc的点数)。之后dp即可。
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005, MAXM = 2000005;struct g { struct node { int to, next; } edge[MAXM]; int head[MAXN], top; g(){ top = 0, memset(head, 0, sizeof head); } void push(int i, int j) { edge[++top] = (node) {j, head[i]}, head[i] = top; }}g, g1;int dfn[MAXN], low[MAXN], stk[MAXN], top = 0, dft = 0;int gp[MAXN], gtop = 0, gsiz[MAXN], vis[MAXN], n, m;void tarjan(int nd){ dfn[nd] = low[nd] = ++dft; stk[++top] = nd, vis[nd] = 1; for (int i = g.head[nd]; i; i = g.edge[i].next) { int to = g.edge[i].to; if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]); else if (vis[to]) low[nd] = min(low[nd], dfn[to]); } if (dfn[nd] == low[nd]) { int now; ++gtop; do { now = stk[top--], vis[now] = 0, gp[now] = gtop, gsiz[gtop]++; } while (now != nd); }}long long x;set<pair<int,int> > hst;int dp[MAXN], cnt[MAXN];int dfs(int nd){ if (dp[nd] != -1) return dp[nd]; dp[nd] = gsiz[nd]; for (int i = g1.head[nd]; i; i = g1.edge[i].next) dp[nd] = max(dp[nd], dfs(g1.edge[i].to)+gsiz[nd]); return dp[nd];}int dfs_cnt(int nd){ if (cnt[nd] != -1) return cnt[nd]; if (!g1.head[nd]) return 1%x; cnt[nd] = 0; for (int i = g1.head[nd]; i; i = g1.edge[i].next) { int to = g1.edge[i].to; if (dp[nd] == dp[to] + gsiz[nd]) (cnt[nd] += dfs_cnt(to)) %= x; } return cnt[nd];}void work(){ for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (int i = 1; i <= n; i++) for (int j = g.head[i]; j; j = g.edge[j].next) { int to = g.edge[j].to; if (gp[i] != gp[to] && !hst.count(make_pair(gp[i], gp[to]))) { hst.insert(make_pair(gp[i], gp[to])); g1.push(gp[to], gp[i]); // G^R } } memset(dp, -1, sizeof dp), memset(cnt, -1, sizeof cnt); int ans1; long long ans2; ans1 = ans2 = 0; for (int i = 1; i <= gtop; i++) ans1 = max(ans1, dfs(i)); for (int i = 1; i <= gtop; i++) if (dfs(i) == ans1) (ans2 += dfs_cnt(i)) %= x; printf("%d\n%lld\n", ans1, ans2);}int main(){ scanf("%d%d%lld", &n, &m, &x); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v), g.push(u, v); } work(); return 0;}
bzoj2208: [JSOI2010] 联通数
缩点后暴力可过..
但是貌似有更好的算法??比如在拓扑图上随意dfs一棵生成树然后dfs序维护??
尚不清楚复杂度是否更优。
#include <bits/stdc++.h>using namespace std;const int MAXN = 2005, MAXM = MAXN*MAXN;struct graph { struct node { int to, next; } edge[MAXM]; int head[MAXN], top; graph(){top = 0, memset(head, 0, sizeof head); } void push(int i, int j) { ++top, edge[top] = (node) {j, head[i]}, head[i] = top; }} g, g1;int dfn[MAXN], dft = 0, low[MAXN], vis[MAXN];int stk[MAXN], top = 0;int gp[MAXN], gtop = 0, gsiz[MAXN], n;void tarjan(int nd){ vis[nd] = 1, dfn[nd] = low[nd] = ++dft, stk[++top] = nd; for (int i = g.head[nd]; i; i = g.edge[i].next) { int to = g.edge[i].to; if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]); else if (vis[to]) low[nd] = min(low[nd], dfn[to]); } if (dfn[nd] == low[nd]) { int now; ++gtop; //printf(" -- Group %d --\n", gtop); do { now = stk[top--]; gp[now] = gtop, gsiz[gtop]++, vis[now] = 0; // cerr << now << " "; } while(now != nd); //puts(""); }}int bfstime = 0;queue<int> que;int lkt[MAXN][MAXN];void work(){ for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (int i = 1; i <= n; i++) for (int j = g.head[i]; j; j = g.edge[j].next) { int to = g.edge[j].to; if (gp[to] != gp[i] && !lkt[gp[i]][gp[to]]) { lkt[gp[i]][gp[to]] = 1; g1.push(gp[i], gp[to]); } } int ans = 0; memset(vis, 0, sizeof vis); for (int i = 1; i <= gtop; i++) { ++bfstime; que.push(i), vis[i] = bfstime; int cnt = 0; while (!que.empty()) { int t = que.front(); que.pop(), cnt += gsiz[t]; for (int i = g1.head[t]; i; i = g1.edge[i].next) { int to = g1.edge[i].to; if (vis[to] != bfstime) vis[to] = bfstime, que.push(to); } } ans += cnt*gsiz[i]; } cout << ans << endl;}char str[2005];int main(){ scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", str+1); for (int j = 1; j <= n; j++) if (str[j] == '1') g.push(i, j); } work(); return 0;}
4.11 更新
今天来一波字符串。
bzoj3172: [Tjoi2013]单词
这个题就比较神了。首先建出AC自动机,然后先求出每个节点的“顺着路过的总数
第一次做反了…
形如
shershersher
的数据可以hack。因为shers不会算入her中去。
#include <bits/stdc++.h>using namespace std;const int MAXN = 3000005;int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0;vector<int> ids[MAXN];int new_node(){ return ++top, fail[top] = fin[top] = 0, memset(chl[top],0, sizeof chl[top]), top; }void push(int &nd, const char *str, int id){ if (nd == 0) nd = new_node(); if (*str == '\0') fin[nd]++, ids[nd].push_back(id); else push(chl[nd][*str-'a'], str+1, id);}struct node { int to, next;} edge[MAXN];int head[MAXN], tp_edge = 0;void push(int i, int j){ ++tp_edge, edge[tp_edge] = (node) {j, head[i]}, head[i] = tp_edge; }int siz[MAXN], n;queue<int> que;void init(){ que.push(root); fail[root] = 0; while (!que.empty()) { int t = que.front(); que.pop(); for (int i = 0; i < 26; i++) if (chl[t][i]) { int p = fail[t]; while (p && !chl[p][i]) p = fail[p]; if (!p) fail[chl[t][i]] = root; else fail[chl[t][i]] = chl[p][i]; que.push(chl[t][i]); push(fail[chl[t][i]], chl[t][i]); } }}long long res[MAXN];long long dp[MAXN];int dfs(int nd){ if (siz[nd] != -1) return siz[nd]; siz[nd] = dp[nd]; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; siz[nd] += dfs(to); } return siz[nd];}long long dfs2(int nd){ if (dp[nd] != -1) return dp[nd]; dp[nd] = fin[nd]; for (int i = 0; i < 26; i++) if (chl[nd][i]) dp[nd] += dfs2(chl[nd][i]); return dp[nd];}char str[MAXN];int main(){ scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", str); push(root, str, i); } init(); memset(siz, -1, sizeof siz); memset(dp, -1, sizeof dp); dfs2(root); dfs(root); for (int i = 1; i <= top; i++) for (int j = 0; j < fin[i]; j++) res[ids[i][j]] = siz[i]; for (int i = 1; i <= n; i++) printf("%lld\n", res[i]); return 0;}
bzoj1090: [SCOI2003]字符串折叠
首先
区间dp是正解,方程容易想到,唯一的字符串trick就是用hashk判断相等。
特别注意取某一区间hash的小技巧。
#include <bits/stdc++.h>using namespace std;const int MAXN = 105;char str[MAXN];int n;unsigned long long hash_tab[MAXN], pwr[MAXN];unsigned long long hash_val(int i, int j){ return hash_tab[j]-hash_tab[i-1]*pwr[j-i+1]; }int dp[MAXN][MAXN];int len(int num){ return num <= 9 ? 1 : (num <= 99 ? 2 : 3); }int dfs(int i, int j){ if (dp[i][j] != -1) return dp[i][j]; if (i == j) return 1; dp[i][j] = INT_MAX; for (int k = i; k < j; k++) dp[i][j] = min(dp[i][j], dfs(i,k)+dfs(k+1,j)); for (int k = 1; k <= j-i+1; k++) { // 枚举每一块长度 if ((j-i+1)%k != 0) continue; int flag = 1; unsigned long long val = 0; for (int p = 0; p < (j-i+1)/k; p++) { if (p == 0) val = hash_val(i+p*k, i+(p+1)*k-1); else if (val != hash_val(i+p*k, i+(p+1)*k-1)) { flag = 0; break; } } if (flag) dp[i][j] = min(dp[i][j], dfs(i, i+k-1)+2+len((j-i+1)/k)); } return dp[i][j];}int main(){ scanf("%s", str+1), n = strlen(str+1); pwr[0] = 1; for (int i = 1; i <= n; i++) pwr[i] = pwr[i-1]*31; for (int i = 1; i <= n; i++) hash_tab[i] = hash_tab[i-1]*31+(str[i]-'A'+1); memset(dp, -1, sizeof dp); cout << dfs(1, n) << endl; return 0;}
bzoj2124: 等差子序列
乍一看和字符串毫无关系…
事实上,存在一个等差数列当且仅当存在三个点
然后对于这种对称的处理思路就两种:
- FFT
- 回文串
FFT貌似不太好处理,但回文串很兹瓷啊。用线段树记录每个点是否存在1/2并维护区间哈希,然后正反算哈希判断是不是相等即可。如果在某一时刻
#include <bits/stdc++.h>using namespace std;const int MAXN = 10005;unsigned long long hash_tab[MAXN*4], hash_rev[MAXN*4], power[MAXN];int lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], top = 0, root = 0;int n, a[MAXN];inline int siz(int nd) { return r[nd]-l[nd]+1; }void build(int &nd, int opl, int opr){ nd = ++top, hash_tab[nd] = hash_rev[nd] = 1, lc[nd] = rc[nd] = 0, l[nd] = opl, r[nd] = opr; if (opl < opr) { build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr); hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]]; hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]]; }}void modify(int nd, int pos){ if (l[nd] == r[nd]) hash_tab[nd] = hash_rev[nd] = 2; else { modify(pos<=(l[nd]+r[nd])/2?lc[nd]:rc[nd], pos); hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]]; hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]]; }}unsigned long long query(int nd, int opl, int opr){ if (l[nd] == opl && r[nd] == opr) return hash_tab[nd]; else { int mid = (l[nd]+r[nd])/2; if (opr <= mid) return query(lc[nd], opl, opr); else if (opl > mid) return query(rc[nd], opl, opr); else return query(lc[nd], opl, mid)+power[mid-opl+1]*query(rc[nd], mid+1, opr); }}unsigned long long query_reversed(int nd, int opl, int opr){ if (l[nd] == opl && r[nd] == opr) return hash_rev[nd]; else { int mid = (l[nd]+r[nd])/2; if (opr <= mid) return query_reversed(lc[nd], opl, opr); else if (opl > mid) return query_reversed(rc[nd], opl, opr); else return power[opr-mid]*query_reversed(lc[nd], opl, mid)+query_reversed(rc[nd], mid+1, opr); }}void init(){ scanf("%d", &n); top = root = 0; build(root, 1, n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]);}int main(){ int T; scanf("%d", &T); power[0] = 1; for (int i = 1; i <= 10000; i++) power[i] = power[i-1]*31; while (T--) { init(); int flag = 0; for (int i = 1; i <= n; i++) { // cerr << query(root, 1, 3) << "--" << query_reversed(root, 1, 3) << endl; if (a[i] <= n-a[i]+1) { if (i >= 2 && i < n && query(root, 1, 2*a[i]-1) != query_reversed(root, 1, 2*a[i]-1)) { flag = 1; break; } } else { int k = 2*(n-a[i]+1)-1; if (i >= 2 && i < n && query(root, n-k+1, n) != query_reversed(root, n-k+1, n)) { flag = 1; break; } } modify(root, a[i]); } if (flag) puts("Y"); else puts("N"); } return 0;}
bzoj3207: 花神的嘲讽计划Ⅰ
首先
注意:hash一定要用ull…
#include <bits/stdc++.h>using namespace std;const int MAXN = 400005, lgn = 20;int n, m, k, bas, sqr;unsigned long long hash_val(int a[], int l, int r){ unsigned long long ans = 0; for (int i = l; i <= r; i++) ans = ans*bas+a[i]; return ans;}struct query { int l, r, dat, id, ans; friend bool operator < (const query &a, const query &b) { return a.l/sqr != b.l/sqr ? a.l < b.l : a.r < b.r; }} q[MAXN];bool cmp(const query &a, const query &b){ return a.id < b.id; }int a[MAXN], tmp[30];unsigned long long d[MAXN], dx[MAXN], qu[MAXN], top = 0;void dx_init(){ memcpy(dx, d, sizeof d); sort(dx+1, dx+top+1);}int dx_num(unsigned long long dat){ return lower_bound(dx+1, dx+top+1, dat)-dx; }int tab[MAXN];int main(){ scanf("%d%d%d", &n, &m, &k), bas = n+1; sqr = sqrt(n); // 分块大小 for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i+k-1 <= n; i++) d[++top] = hash_val(a, i, i+k-1); for (int i = 1; i <= m; i++) { scanf("%d%d", &q[i].l, &q[i].r); q[i].r = q[i].r-k+1; for (int j = 1; j <= k; j++) scanf("%d", &tmp[j]); qu[i] = hash_val(tmp, 1, k); d[++top] = qu[i], q[i].id = i; } dx_init(); // 离散化 for (int i = 1; i+k-1 <= n; i++) a[i] = dx_num(d[i]); for (int i = 1; i <= m; i++) q[i].dat = dx_num(qu[i]); sort(q+1, q+m+1); memset(tab, 0, sizeof tab); int L = q[1].l, R = q[1].r; for (int i = L; i <= R; i++) tab[a[i]]++; q[1].ans = tab[q[1].dat]; for (int i = 2; i <= m; i++) { if (q[i].l > q[i].r) continue; while (L < q[i].l) tab[a[L++]]--; while (L > q[i].l) tab[a[--L]]++; while (R < q[i].r) tab[a[++R]]++; while (R > q[i].r) tab[a[R--]]--; q[i].ans = tab[q[i].dat]; } sort(q+1, q+m+1, cmp); for (int i = 1; i <= m; i++) if (q[i].ans) puts("No"); else puts("Yes"); return 0;}
bzoj1103: [POI2007]大都市meg
看题解dfs序+树状数组就水过去了,
但是写了链剖
然而
玄学啊…当然也可能我写跪了…
链剖
#include <bits/stdc++.h>using namespace std;const int MAXN = 250005;int C[MAXN], n, dstop = 0;int lowbit(int i) { return i&(-i); }void modify(int pos, int dt){ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }int sum(int pos){ int ans = 0; for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];} return ans;}int sum(int l, int r){ return sum(r)-sum(l-1); }struct node { int to, next;} edge[MAXN*2];int head[MAXN], top;void push(int i, int j){ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }int siz[MAXN], id[MAXN], ind[MAXN], fa[MAXN];void dfs1(int nd){ siz[nd] = 1; for (int i = head[nd]; i; i = edge[i].next) dfs1(edge[i].to), siz[nd] += siz[edge[i].to], fa[edge[i].to] = nd;}void dfs2(int nd, int from = 0){ id[nd] = ++dstop, ind[nd] = from, modify(id[nd], 1); int hev = 0; for (int i = head[nd]; i; i = edge[i].next) if (siz[edge[i].to] > siz[hev]) hev = edge[i].to; if (!hev) return; dfs2(hev, from); for (int i = head[nd]; i; i = edge[i].next) if (edge[i].to != hev) dfs2(edge[i].to, edge[i].to);}void change(int nd){ modify(id[nd], -1); }int ask(int nd){ int ans = 0; while (nd) { // cout << nd << endl; ans += sum(id[ind[nd]], id[nd]), nd = fa[ind[nd]]; } return ans;}int main(){ scanf("%d", &n); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); if (u > v) swap(u,v); push(u, v); } dfs1(1), dfs2(1); int m; scanf("%d", &m); for (int i = 1; i <= m+n-1; i++) { char s; int u, v; scanf("\n%c", &s); if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); } else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)-1); } else throw; } return 0;}
LCT(TLE)
#include <bits/stdc++.h>using namespace std;const int MAXN = 250005;int chl[MAXN][2], dat[MAXN], hv[MAXN], stk[MAXN], stktop = 0, fa[MAXN];int rev[MAXN], n, m;bool is_rt(int nd){ return nd != chl[fa[nd]][0] && nd != chl[fa[nd]][1]; }void update(int nd){ dat[nd] = dat[chl[nd][0]] + dat[chl[nd][1]] + hv[nd];}void pdw(int nd){ if (!rev[nd]) return; int &lc = chl[nd][0], &rc = chl[nd][1]; rev[nd] = 0; if (lc) rev[lc] ^= 1; if (rc) rev[rc] ^= 1; swap(lc, rc);}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 (!is_rt(p)) chl[g][tg] = nd; chl[nd][tp^1] = p, chl[p][tp] = son; fa[son] = p, fa[p] = nd, fa[nd] = g; update(p), update(nd);}void splay(int nd){ stk[stktop = 1] = nd; for (int i = nd; !is_rt(i); i = fa[i]) stk[++stktop] = fa[i]; while (stktop) pdw(stk[stktop--]); 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; } else 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, update(x);}void make_rt(int x){ access(x), splay(x), rev[x] ^= 1; }void link(int i, int j){ make_rt(j), fa[j] = i, access(j); }void change(int nd){ make_rt(nd), splay(nd), hv[nd]--, update(nd); }int ask(int nd){ make_rt(1), access(nd), splay(nd); return hv[nd]+dat[chl[nd][0]]; }int main(){ scanf("%d", &n); for (int i = 2; i <= n; i++) hv[i] = 1; for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); if (u > v) swap(u, v); link(u, v); } scanf("%d", &m); for (int i = 1; i <= n+m-1; i++) { char c; int u, v; scanf("\n%c", &c); if (c == 'W') { scanf("%d", &u), printf("%d\n", ask(u)); } else if (c == 'A') { scanf("%d%d", &u, &v), change(max(u, v)); } } return 0;}
dfn&BIT
#include <bits/stdc++.h>using namespace std;const int MAXN = 250005;int C[MAXN], n, dstop = 0;int lowbit(int i) { return i&(-i); }void modify(int pos, int dt){ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }int sum(int pos){ int ans = 0; for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];} return ans;}struct node { int to, next;} edge[MAXN];int head[MAXN], top = 0;void push(int i, int j){ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }int depth[MAXN], dfi[MAXN], dfo[MAXN], dft = 0;void dfs(int nd){ dfi[nd] = ++dft; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; depth[to] = depth[nd]+1; dfs(to); } dfo[nd] = dft;}void change(int nd){ modify(dfi[nd], 1), modify(dfo[nd]+1, -1); }int ask(int nd){ return depth[nd]-sum(dfi[nd]); }int main(){ scanf("%d", &n); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); if (u > v) swap(u,v); push(u, v); } depth[1] = 0, dfs(1); int m; scanf("%d", &m); for (int i = 1; i <= n+m-1; i++) { char s; int u, v; scanf("\n%c", &s); if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); } else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)); } else throw; } return 0;}
4.13
bzoj3506: [Cqoi2014]排序机械臂
题面传送门
就是splay维护最小值和最小值位置,加上反转操作即可。
然而debug能力是硬伤…
注意重复元素的处理,就是
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], stktop = 0;int top = 0, min_pos[MAXN], siz[MAXN], root = 0;long long min_val[MAXN], dat[MAXN];void update(int nd){ min_val[nd] = min(dat[nd], min(min_val[chl[nd][0]], min_val[chl[nd][1]])); min_pos[nd] = min_val[nd] == min_val[chl[nd][0]] ? min_pos[chl[nd][0]] : (min_val[nd] == dat[nd] ? nd : min_pos[chl[nd][1]]); siz[nd] = siz[chl[nd][0]] + siz[chl[nd][1]] + 1;}inline int new_node(long long d) { return ++top, dat[top] = d, update(top), top;}void pdw(int nd){ if (!rev[nd]) return; int &lc = chl[nd][0], &rc = chl[nd][1]; if (lc) rev[lc] ^= 1; if (rc) rev[rc] ^= 1; swap(lc, rc), rev[nd] ^= 1;}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]; fa[son] = son==0?0:p, fa[p] = nd, fa[nd] = g; chl[g][tg] = g==0?0:nd, chl[nd][tp^1] = p, chl[p][tp] = son; root = g?root:nd; update(p), update(nd);}void splay(int nd, int tar = 0){ stk[stktop = 1] = nd; for (int i = nd; fa[i]; i = fa[i]) stk[++stktop] = fa[i]; for (; stktop; stktop--) pdw(stk[stktop]); while (fa[nd] != tar) { int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p; if (g == tar) {zig(nd); break; } else if (tp == tg) zig(p), zig(nd); else zig(nd), zig(nd); }}void dfs(int nd){ if (!nd) return; pdw(nd); dfs(chl[nd][0]); cerr << dat[nd] << " "; dfs(chl[nd][1]);}void insert(long long nd){ if (root == 0) root = new_node(nd); else { chl[root][1] = new_node(nd), fa[top] = root; splay(top), update(top); // dfs(top); }}int get_min(){ splay(min_pos[root]); int ans = siz[chl[root][0]]+1; return ans;}int get_by_order(int k){ int nd = root; k--; // have k element on left while (nd) { pdw(nd), update(nd); if (siz[chl[nd][0]] == k) break; nd = siz[chl[nd][0]]>k?chl[nd][0]:(k -= siz[chl[nd][0]]+1, chl[nd][1]); } return nd;}int get_segment(int l, int r){ if (l == 1 && r == siz[root]) return root; if (l == 1) return splay(get_by_order(r+1)), chl[root][0]; if (r == siz[root]) return splay(get_by_order(l-1)), chl[root][1]; return splay(get_by_order(l-1)), splay(get_by_order(r+1), root), chl[chl[root][1]][0];}void del_root(){ int t = get_segment(siz[chl[root][0]]+1, siz[chl[root][0]]+1); int tp = chl[fa[t]][0] != t; chl[fa[t]][tp] = 0; for (int i = fa[t]; i; i = fa[i]) update(i); fa[t] = 0;}void reverse(int l, int r){ int t = get_segment(l, r); rev[t] ^= 1;}int ans(){ int ret = get_min(); reverse(1, ret); splay(min_pos[root]), del_root(); return ret;}int n;int main(){ memset(min_val, 127/3, sizeof min_val); scanf("%d", &n); for (int i = 1; i <= n; i++) { int u; scanf("%d", &u); insert((long long)u*(n+1)+i); } for (int i = 1; i <= n; i++) printf("%d ", ans()+i-1); return 0;}
bzoj3530: [Sdoi2014]数数
大爷题解:http://blog.csdn.net/aarongzk/article/details/50472209#
就是AC自动机上dp,然而数位dp仍然跪烂…要注意前导零的处理。
AC自动机忘记push儿子调试1h…
#include <bits/stdc++.h>using namespace std;const int MAXL = 1505;int vis[MAXL];struct ACM { struct node { int chl[10]; int finished, fail; node() { memset(chl, 0, sizeof chl), finished = fail = 0; } } tree[MAXL]; int top, root; ACM() { top = root = 0; } inline int new_node() { return ++top; } void insert(int &nd, const char *str) { if (!nd) nd = new_node(); if (*str == '\0') tree[nd].finished = 1, vis[nd] = 1; else insert(tree[nd].chl[*str-'0'], str+1); } queue<int> que; void init() { tree[root].fail = 0, que.push(root); while (!que.empty()) { int nd = que.front(); que.pop(); vis[nd] |= vis[tree[nd].fail]; for (int i = 0; i < 10; i++) { if (!tree[nd].chl[i]) continue; int p = tree[nd].fail; while (p && !tree[p].chl[i]) p = tree[p].fail; if (!p) tree[tree[nd].chl[i]].fail = root; else tree[tree[nd].chl[i]].fail = tree[p].chl[i]; que.push(tree[nd].chl[i]); } } ; } int trans(int nd, int ths) { if (tree[nd].chl[ths]) return tree[nd].chl[ths]; int p = tree[nd].fail; while (p && !tree[p].chl[ths]) p = tree[p].fail; if (!p) return root; else return tree[p].chl[ths]; }} ac;long long dp[1500][MAXL][3]; // 1 随意 0 不随意char str[MAXL]; int s[MAXL];long long mod = 1e9+7;int n, m;int main(){ memset(vis, 0, sizeof vis); scanf("%s", str+1); n = strlen(str+1); for (int i = 1; i <= n; i++) s[i] = str[i]-'0'; scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%s", str); ac.insert(ac.root, str); } long long ans = 0; ac.init(); memset(dp, 0, sizeof dp); for (int i = 1; i < 10; i++) if (!vis[ac.trans(ac.root, i)]) dp[2][ac.trans(ac.root, i)][0]++; for (int i = 2; i < n; i++) for (int j = 1; j <= ac.top; j++) for (int k = 0; k < 10; k++) if (!vis[ac.trans(j, k)]) (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod; for (int i = 2; i <= n; i++) for (int j = 1; j <= ac.top; j++) (ans += dp[i][j][0]) %= mod; // 前导0 memset(dp, 0, sizeof dp); for (int i = 1; i <= s[1]; i++) if (!vis[ac.trans(ac.root, i)]) dp[2][ac.trans(ac.root, i)][i == s[1]]++; for (int i = 2; i <= n; i++) { for (int j = 1; j <= ac.top; j++) for (int k = 0; k < 10; k++) { if (vis[ac.trans(j, k)]) continue; (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod; if (k < s[i]) (dp[i+1][ac.trans(j, k)][0] += dp[i][j][1]) %= mod; else if (k == s[i]) (dp[i+1][ac.trans(j, k)][1] += dp[i][j][1]) %= mod; } } for (int i = 1; i <= ac.top; i++) (ans += dp[n+1][i][0]+dp[n+1][i][1]) %= mod; cout << ans << endl; return 0;}
- bzoj刷题记录4.10-4.14
- BZOJ刷题记录
- BZOJ刷题记录(2014)
- BZOJ 刷题记录 PART 1
- BZOJ 刷题记录 PART 2
- BZOJ 刷题记录 PART 3
- BZOJ 刷题记录 PART 4
- BZOJ 刷题记录 PART 5
- BZOJ 刷题记录 PART 6
- bzoj刷题记录2017.4.2-4.4
- bzoj刷题记录:4.5-4.9
- bzoj刷题记录4.15-4.16
- bzoj刷题记录4.17-4.21
- bzoj刷题记录4.25-5.1
- bzoj刷题记录5.6-5.10
- bzoj刷题记录5.11-5.15
- BZOJ刷题记录(施工到AFO)
- OI刷题记录
- android从放弃到坚持放弃第六课(上)
- Material Capture(材质捕捉) shader 学习
- uvalive 5004 hdu 3709 Balanced Number 左右数字权和相等(数位dp)
- JavaScript 中的遍历
- C# 在多线程中调用Timer
- bzoj刷题记录4.10-4.14
- GPIO
- C语言复习笔记 9
- 机器学习算法——信息熵
- 【python学习笔记】1- 相关环境安装
- MySQL数据库(入门)(一)
- shell中变量的变量与eval命令
- 团体程序设计天梯赛L3-013 非常弹的球
- 【密码学】SHA-1加密原理及其Java实现