[Test for PKU]
2016-5-16 AM
[hdu 5289]Assignment
枚举左端点,二分右端点
不可以枚举最小值,因为会有重复
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 100010 using namespace std; typedef long long ll; int n; ll k; int lg[maxn * 3]; ll a[maxn], t[maxn][20], g[maxn][20]; ll askmx(int l, int r){ int len = r - l + 1, LG = lg[len]; return max(t[l][LG], t[r - (1 << LG) + 1][LG]); } ll askmn(int l, int r){ int len = r - l + 1, LG = lg[len]; return min(g[l][LG], g[r - (1 << LG) + 1][LG]); } int main(){ int test; scanf("%d", &test); int la = 0; for(int i = 1, p = 0; i <= 300000; i <<= 1){ for(int j = la; j < i; j ++) lg[j] = p - 1; la = i; p ++; } while(test --){ scanf("%d%lld", &n, &k); for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]); for(int i = 1; i <= n; i ++) g[i][0] = t[i][0] = a[i]; for(int j = 1; 1 << j <= n; j ++){ int ln = 1 << j-1; for(int i = 1; i + ln - 1 <= n; i ++) t[i][j] = max(t[i][j-1], t[i+ln][j-1]), g[i][j] = min(g[i][j-1], g[i+ln][j-1]); } ll ans = 0; for(int i = 1; i <= n; i ++){ int l = i, r = n; while(l < r){ int mid = l + (r - l + 1) / 2; ll mx = askmx(i, mid), mn = askmn(i, mid); if(mx - mn < k)l = mid; else r = mid - 1; } ans += r - i + 1; } printf("%lld\n", ans); } return 0; }
[hdu 5293]Tree chain problem
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #define maxn 200010 using namespace std; const int root = 1; int n, m; typedef long long ll; struct Edge{int to, nxt;}edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v){ edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v]}; h[v] = cnt; } int fa[maxn], dep[maxn], anc[maxn][20]; int dfs_clock, In[maxn], Out[maxn]; ll t[maxn], dp[maxn]; void Init(){ memset(fa, 0, sizeof fa); memset(dep, 0, sizeof dep); memset(anc, 0, sizeof anc); memset(h, 0, sizeof h); cnt = 0; memset(t, 0, sizeof t); memset(dp, 0, sizeof dp); dfs_clock = 0; } void dfs(int u){ dep[u] = dep[fa[u]] + 1; In[u] = ++ dfs_clock; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; anc[v][0] = fa[v] = u; dfs(v); } Out[u] = ++ dfs_clock; } int LCA(int p, int q){ if(dep[p] < dep[q])swap(p, q); int log = 1; for(; 1 << log <= dep[p]; log ++); log --; for(int i = log; i >= 0; i --) if(dep[anc[p][i]] >= dep[q]) p = anc[p][i]; if(p == q)return p; for(int i = log; i >= 0; i --) if(anc[p][i] != anc[q][i]) p = anc[p][i], q = anc[q][i]; return fa[p]; } #define lowbit(i) i & (~i + 1) void update(int pos, ll val){ for(int i = pos; i <= dfs_clock; i += lowbit(i)) t[i] += val; } ll ask(int pos){ ll ret = 0; for(int i = pos; i; i -= lowbit(i)) ret += t[i]; return ret; } int fr[maxn], to[maxn], val[maxn]; vector<int> pt[maxn]; void DP(int u){ ll g = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; DP(v), g += dp[v]; } update(In[u], g); update(Out[u] + 1, -g); ll ans = g; for(int i = 0; i < pt[u].size(); i ++){ int nw = pt[u][i]; ans = max(ans, ask(Out[fr[nw]]) + ask(Out[to[nw]]) + (ll)val[nw] - g); } dp[u] = ans; update(In[u], -ans); update(Out[u] + 1, ans); } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%d%d", &n, &m); Init(); int u, v, d; for(int i = 1; i < n; i ++){ scanf("%d%d", &u, &v); add(u, v); } for(int i = 1; i <= n; i ++) pt[i].clear(); dfs(root); for(int j = 1; 1 << j <= n; j ++) for(int i = 1; i <= n; i ++) anc[i][j] = anc[anc[i][j-1]][j-1]; for(int i = 1; i <= m; i ++){ scanf("%d%d%d", &fr[i], &to[i], &val[i]); pt[LCA(fr[i], to[i])].push_back(i); } DP(root); printf("%d\n", dp[root]); } return 0; }
[hdu 5323]Solve this interesting problem
搜索,扩展它的父节点是什么,线段树的层数不会超过12层,复杂度可靠
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long ll; ll n; void dfs(ll l, ll r){ if(l < 0)return; if(l == 0){ if(n == -1)n = r; else n = min(n, r); } if(n != -1 && r >= n)return; ll len = r - l + 1; if(len > (l - 1) * 2)return; dfs(l - len, r); dfs(l - len - 1, r); dfs(l, r + len - 1); dfs(l, r + len); } int main(){ ll l, r; while(scanf("%lld%lld", &l, &r) == 2){ n = -1; dfs(l, r); printf("%lld\n", n); } return 0; }
[hdu 5324]Boring Class
Cdq分治,三位偏序输出方案字典序最小
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 50010 using namespace std; int h[maxn], cnt, n; struct opt{int a, b, i, f, pre;}q[maxn]; #define lowbit(i) (i & (~i + 1)) namespace BIT{ int n, tim, t[maxn], vis[maxn], pos[maxn]; void init(){tim ++;} void update(int aaa, int val, int p){ for(int i = aaa; i <= n; i += lowbit(i)) if(vis[i] == tim){ if(val > t[i] || (val == t[i] && pos[i] > p)) t[i] = val, pos[i] = p; } else vis[i] = tim, t[i] = val, pos[i] = p; } pair<int, int> ask(int aaa){ int ret = 0, p = n + 1; for(int i = aaa; i; i -= lowbit(i)) if(vis[i] == tim) if(t[i] > ret || (t[i] == ret && p > pos[i])) ret = t[i], p = pos[i]; if(ret == 0)p = 0; return make_pair(ret, p); } } bool cmpi(const opt& a, const opt& b){ return a.i < b.i; } bool cmpab(const opt& a, const opt& b){ if(a.a == b.a)return a.i > b.i; return a.a < b.a; } void solve(int l, int r){ if(l == r)return; int mid = l + r >> 1; solve(mid + 1, r); sort(q + l, q + r + 1, cmpab); BIT::init(); for(int i = l; i <= r; i ++){ if(q[i].i <= mid){ pair<int, int> nw = BIT::ask(q[i].b); nw.first ++; if((q[i].f == nw.first && q[i].pre > nw.second) || q[i].f < nw.first) q[i].f = nw.first, q[i].pre = nw.second; } else BIT::update(q[i].b, q[i].f, q[i].i); } sort(q + l, q + r + 1, cmpi); solve(l, mid); } int amt, ans[maxn]; int main(){ while(scanf("%d", &n) == 1){ cnt = 0; for(int i = 1; i <= n; i ++)scanf("%d", &q[i].a); for(int i = 1; i <= n; i ++)scanf("%d", &q[i].b), q[i].b = -q[i].b, h[i] = q[i].b; sort(h + 1, h + 1 + n); cnt = unique(h + 1, h + 1 + n) - h - 1; for(int i = 1; i <= n; i ++) q[i].b = lower_bound(h + 1, h + 1 + cnt, q[i].b) - h; BIT::n = cnt; for(int i = 1; i <= n; i ++) q[i].i = i, q[i].f = 1, q[i].pre = 0; solve(1, n); sort(q + 1, q + n + 1, cmpi); int p = 0, mx = 0; for(int i = 1; i <= n; i ++) if(q[i].f > mx)mx = q[i].f, p = i; amt = 0; while(p){ans[++ amt] = p, p = q[p].pre;} printf("%d\n", amt); for(int i = 1; i < amt; i ++) printf("%d ", ans[i]);printf("%d", ans[amt]);puts(""); } return 0; }
2016-5-16 PM
[BZOJ]Kernel Knights
图的特殊性,图是二分图,环是简单环
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 500010 using namespace std; int n; int to[maxn], h[maxn], cnt, deg[maxn], col[maxn], que[maxn], head, tail; void add(int u, int v){to[u] = v, deg[v] ++;} void BFS(int u){ col[u] = 2; while(true){ if(col[to[u]])break; deg[to[u]] --; if(deg[to[u]] == 0 || col[u] == 2){ col[to[u]] = col[u] ^ 1; u = to[u]; } else break; } } void Col(int u){ col[u] = 2; while(true){ if(col[to[u]])break; col[to[u]] = col[u] ^ 1; u = to[u]; } } int main(){ scanf("%d", &n); int v; for(int i = 1; i <= n; i ++) scanf("%d", &v), add(i, v); for(int i = n + 1; i <= n * 2; i ++) scanf("%d", &v), add(i, v); n <<= 1; for(int i = 1; i <= n; i ++) if(!deg[i] && !col[i])BFS(i); for(int i = 1; i <= n; i ++) if(!col[i])Col(i); for(int i = 1; i <= n; i ++) if(col[i] == 2)printf("%d ", i); return 0; }
Wheels
样例输入
1
5
0 0 6
6 8 4
-9 0 3
6 16 4
0 -11 4
样例输出
1 clockwise
3/2 counterclockwise
2 counterclockwise
3/2 clockwise
not moving
没有处理好相交圆的关系,以为直接扫描就可以
实际上只要BFS一遍就可以了。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 10010 using namespace std; typedef long long ll; int n; struct opt{ ll x, y, r; ll p, q, a; void read(){ scanf("%lld%lld%lld", &x, &y, &r); p = q = a = 0; } }o[maxn]; ll gcd(ll a, ll b){ return !b ? a : gcd(b, a % b); } #define sqr(x) ((x) * (x)) ll dist(const opt& a, const opt& b){ return sqr(a.x - b.x) + sqr(a.y - b.y); } bool cross(const opt& a, const opt& b){ return dist(a, b) <= sqr(a.r + b.r); } void getans(int i, int j){ o[j].a = o[i].a ^ 1; o[j].p = o[i].p * o[i].r; o[j].q = o[i].q * o[j].r; ll d = gcd(o[j].p, o[j].q); o[j].p /= d, o[j].q /= d; } struct Edge{int to, nxt;}edge[1000010]; int h[maxn], cnt; void add(int u, int v){ edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v]}; h[v] = cnt; } void dfs(int u){ for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(o[v].a)continue; getans(u, v); dfs(v); } } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%d", &n); memset(h, 0, sizeof h); cnt = 0; for(int i = 1; i <= n; i ++) o[i].read(); o[1].p = o[1].q = 1; o[1].a = 2; for(int i = 1; i <= n; i ++) for(int j = i + 1; j <= n; j ++) if(cross(o[i], o[j])) add(i, j); dfs(1); for(int i = 1; i <= n; i ++){ if(o[i].a == 0){ printf("not moving\n"); continue; } if(o[i].q == 1)printf("%lld ", o[i].p); else printf("%lld/%lld ", o[i].p, o[i].q); if(o[i].a == 2)printf("clockwise\n"); else if(o[i].a == 3)printf("counterclockwise\n"); } } return 0; }
[poj]Atlantis
矩形面积并。
注意标记就可以了
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 200010 using namespace std; const double eps = 1e-5; int n; struct opt{ double x, a, b; int tp; int l, r; opt(double x_ = 0, double a_ = 0, double b_ = 0, int tp_ = 0, int l_ = 0, int r_ = 0){ x = x_; a = a_; b = b_; tp = tp_; l = l_; r = r_; } }q[maxn << 2]; bool cmp(const opt& a, const opt& b){ return a.x < b.x; } int amt; double h[maxn << 2]; int cnt; struct Node{ int vis; double len, cov; void clear(){vis = len = cov = 0;} }t[maxn << 2]; #define lc id << 1 #define rc id << 1 | 1 void pushup(int id){if(t[id].vis == 0)t[id].cov = t[lc].cov + t[rc].cov;} void build(int id, int l, int r){ t[id].clear(); if(l + 1 == r){ t[id].len = h[r] - h[l]; return; } int mid = l + r >> 1; build(lc, l, mid); build(rc, mid, r); t[id].len = t[lc].len + t[rc].len; } void update(int id, int l, int r, int L, int R, int val){ if(L <= l && r <= R){ if(val == 1){ t[id].vis ++; t[id].cov = t[id].len; } else{ t[id].vis --; if(t[id].vis == 0){ if(l == r)t[id].cov = 0; else t[id].cov = t[lc].cov + t[rc].cov; } } return; } int mid = l + r >> 1; if(L < mid)update(lc, l, mid, L, R, val); if(R > mid)update(rc, mid, r, L, R, val); pushup(id); } int main(){ int Case = 0; while(scanf("%d", &n) && n){ double a, b, c, d; cnt = amt = 0; for(int i = 1; i <= n; i ++){ scanf("%lf%lf%lf%lf", &a, &b, &c, &d); h[++ cnt] = b, h[++ cnt] = d; q[++ amt] = opt(a, b, d, 1); q[++ amt] = opt(c, b, d, -1); } sort(h + 1, h + 1 + cnt); cnt = unique(h + 1, h + 1 + cnt) - h - 1; for(int i = 1; i <= amt; i ++){ q[i].l = lower_bound(h + 1, h + 1 + cnt, q[i].a - eps) - h; q[i].r = lower_bound(h + 1, h + 1 + cnt, q[i].b - eps) - h; } sort(q + 1, q + 1 + amt, cmp); build(1, 1, cnt); double ans = 0; for(int i = 1; i <= amt; i ++){ ans += t[1].cov * (q[i].x - q[i-1].x); if(q[i].l + 1 > q[i].r)continue; update(1, 1, cnt, q[i].l, q[i].r, q[i].tp); } printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++ Case, ans); } return 0; }
2016-5-17 AM
[hdu 3394]Railway
题意好难懂啊。。
题目描述
There are some locations in a park, and some of them are connected by roads. The park manger needs to build some railways along the roads, and he would like to arrange tourist routes to each circuit. If a railway belongs to more than one tourist routes, there might be clash on it, and if a railway belongs to none tourist route, it doesn’t need to build.
Now we know the plan, and can you tell us how many railways are no need to build and how many railways where clash might happen.
/*Calsh(冲突)*/
输入
The Input consists of multiple test cases. The first line of each test case contains two integers, n (0 < n <= 10000), m (0 <= m <= 100000), which are the number of locations and the number of the railways. The next m lines, each line contains two integers, u, v (0 <= u, v< n), which means the manger plans to build a railway on the road between u and v.
You can assume that there is no loop and no multiple edges.
The last test case is followed by two zeros on a single line, which means the end of the input.
输出
Output the number of railways that are no need to build, and the number of railways where clash might happen. Please follow the format as the sample.
样例输入
8 10
0 1
1 2
2 3
3 0
3 4
4 5
5 6
6 7
7 4
5 7
0 0
样例输出
1 5
//点双联通分量
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #define maxn 100010 using namespace std; struct Edge{ int to, nxt; }edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v){ edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v]}; h[v] = cnt; } int n, m; vector<int> V; int bccno[maxn], low[maxn], pre[maxn], bcc_cnt, dfs_clock; stack<int> S; int ans1, ans2; void solve(){ int Count = 0; for(int i = 0; i < V.size(); i ++){ int nw = V[i]; for(int j = h[nw]; j; j = edge[j].nxt){ int v = edge[j].to; if(bccno[v] == bcc_cnt)Count ++; } } Count >>= 1; if(Count > V.size())ans2 += Count; else if(Count < V.size())ans1 += Count; } void dfs(int u, int f){ low[u] = pre[u] = ++ dfs_clock; S.push(u); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(!pre[v]){ dfs(v, u); low[u] = min(low[u], low[v]); if(low[v] >= pre[u]){ bcc_cnt ++; V.clear(); for(;;){ int w = S.top();S.pop(); bccno[w] = bcc_cnt; V.push_back(w); if(w == v)break; } V.push_back(u), bccno[u] = bcc_cnt; solve(); } } else if(v != f)low[u] = min(low[u], pre[v]); } } int main(){ while(scanf("%d%d", &n, &m) && n){ memset(h, 0, sizeof h); cnt = 1; memset(bccno, 0, sizeof bccno); memset(low, 0, sizeof low); memset(pre, 0, sizeof pre); bcc_cnt = dfs_clock = 0; while(!S.empty())S.pop(); int u, v; for(int i = 1; i <= m; i ++) scanf("%d%d", &u, &v), add(u + 1, v + 1); ans1 = ans2 = 0; for(int i = 1; i <= n; i ++) if(!pre[i])dfs(i, 0); printf("%d %d\n", ans1, ans2); } return 0; }
[POJ]Boatherds
求一棵树上是否存在长度为k的路径
点分治就可以了
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 10010 using namespace std; int n; struct Edge{ int to, nxt, dis; }edge[maxn << 1]; int h[maxn], cnt; void add(int u, int v, int d){ edge[++ cnt] = (Edge){v, h[u], d}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v], d}; h[v] = cnt; } int size[maxn], Sum, G; bool vis[maxn]; int Need; void getG(int u, int fa){ size[u] = 1; int f = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v] || v == fa)continue; getG(v, u); size[u] += size[v]; f = max(f, size[v]); } f = max(f, Sum - size[u]); if(f * 2 <= Sum)G = u; } typedef pair<int, int> pii; pii w[maxn];int C; void dfs(int u, int fa, int t, int dis){ if(dis > Need)return; w[++ C] = make_pair(dis, t); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v] || v == fa)continue; dfs(v, u, t, edge[i].dis + dis); } } bool solve(int u){ vis[u] = true; int num = 0; C = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; dfs(v, u, ++ num, edge[i].dis); } sort(w + 1, w + 1 + C); int it = C; for(int i = 1; i <= C; i ++) if(w[i].first == Need)return true; for(int i = 1; i <= C; i ++){ while(i < it && w[i].first + w[it].first > Need)it --; if(i >= it)break; int j; for(j = it; j > i && w[i].first + w[it].first == Need; j --) if(w[i].second != w[j].second)return true; if(w[i + 1].first != w[i].first)it = j; } for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; Sum = size[v]; G = v; getG(v, u); if(solve(G))return true; }return false; } int main(){ while(scanf("%d", &n) && n){ memset(vis, 0, sizeof vis); memset(h, 0, sizeof h); cnt = 0; int ch, v, d; for(int i = 1; i <= n; i ++) while(scanf("%d", &v) && v) scanf("%d", &d), add(i, v, d); while(scanf("%d", &d) && d){ Need = d; memset(vis, 0, sizeof vis); Sum = n; G = 1; getG(1, 0); if(solve(1))puts("AYE"); else puts("NAY"); } puts("."); } return 0; }
[hdu 4328]Cut the cake
求一个图中最大蓝色/红色/红蓝相间子矩形周长
悬线法,求出up,lf,rg计算即可。
红蓝相间的话把奇数点反色。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 1010 using namespace std; char str[maxn][maxn]; int n, m; int a[maxn][maxn], ans; int up[maxn][maxn], lf[maxn][maxn], rg[maxn][maxn]; void init(){ memset(up, 0, sizeof up); memset(lf, 0, sizeof lf); memset(rg, 0, sizeof rg); } void dp(){ init(); for(int i = 1; i <= n; i ++){ int lo = 0, hi = m + 1; for(int j = 1; j <= m; j ++){ if(a[i][j])up[i][j] = lf[i][j] = 0, lo = j; else{ up[i][j] = up[i-1][j] + 1; lf[i][j] = i == 1 ? lo + 1 : max(lf[i-1][j], lo + 1); } } for(int j = m; j >= 1; j --){ if(a[i][j])hi = j, rg[i][j] = m + 1; else rg[i][j] = i == 1 ? hi - 1 : min(rg[i-1][j], hi - 1); } for(int j = 1; j <= m; j ++) if(up[i][j])ans = max(ans, up[i][j] + rg[i][j] - lf[i][j] + 1); } } int main(){ int test, Case = 0; scanf("%d", &test); while(test --){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%s", str[i] + 1); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) a[i][j] = str[i][j] == 'B'; ans = 2; dp(); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) a[i][j] = str[i][j] == 'R'; dp(); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) if(i + j & 1)a[i][j] = str[i][j] == 'R'; else a[i][j] = str[i][j] == 'B'; dp(); for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) if(i + j & 1)a[i][j] = str[i][j] == 'B'; else a[i][j] = str[i][j] == 'R'; dp(); printf("Case #%d: %d\n", ++Case, ans << 1); } return 0; }
[Brackets]
求括号匹配(有深度限制的方案数)
//dp[i][j][k]表示有i个(,j个),相差最大为k的方案数,转移即可,高精度。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 52 using namespace std; #define md 10000 struct bign{ int a[110], len; void clear(){ memset(a, 0, sizeof a); len = 0; } void jw(){ len += 2; for(int i = 1; i < len; i ++) a[i + 1] += a[i] / md, a[i] %= md; while(len && a[len] == 0)len --; } void print(){ printf("%d", a[len]); for(int i = len - 1; i >= 1; i --) printf("%04d", a[i]); puts(""); } }; typedef bign ll; ll operator + (const ll &a, const ll &b){ ll c; c.clear(); c.len = max(a.len, b.len); for(int i = 1; i <= c.len; i ++) c.a[i] = a.a[i] + b.a[i]; c.jw(); return c; } ll f[maxn][maxn][maxn]; int main(){ int n = 51, k; f[0][0][0].len = f[0][0][0].a[1] = 1; for(int i = 0; i < n; i ++){ for(int j = 0; j <= i; j ++){ for(int k = 0; k <= n; k ++) f[i+1][j][max(k, i + 1 - j)] = f[i+1][j][max(k, i + 1 - j)] + f[i][j][k]; for(int k = 0; k <= n; k ++) f[i][j+1][max(k, i - j - 1)] = f[i][j+1][max(k, i - j - 1)] + f[i][j][k]; } } int Case = 0; while(scanf("%d%d", &n, &k)){ if(n == 0 && k == 0)break; printf("Case %d: ", ++ Case); f[n][n][k].print(); puts(""); } return 0; }
[POJ]Life Forms
后缀自动机,输出方案从根搜索就可以了。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <map> #define maxn 2000010 using namespace std; int n; struct Node{ int len, link, vis, la; map<int, int> nxt; void clr(){ nxt.clear(); la = vis = len = link = 0; } }st[maxn]; int root, last, size; void init(){ for(int i = 1; i <= size; i ++) st[i].clr(); root = last = size = 0; st[root].clr(); st[root].link = -1; } char str[1010]; void Extend(int c, int Id){ int p = last, q = st[p].nxt[c]; if(q){ if(st[q].len == st[p].len + 1) last = q; else{ int clone = ++ size; st[clone] = st[q]; st[clone].len = st[p].len + 1; for(; ~p && st[p].nxt[c] == q; p = st[p].link) st[p].nxt[c] = clone; st[q].link = clone; last = clone; } } else{ int cur = ++ size; st[cur].clr(); st[cur].len = st[p].len + 1; for(; ~p && st[p].nxt[c] == 0; p = st[p].link) st[p].nxt[c] = cur; if(p == -1) st[cur].link = root; else{ q = st[p].nxt[c]; if(st[q].len == st[p].len + 1) st[cur].link = q; else{ int clone = ++ size; st[clone] = st[q]; st[clone].len = st[p].len + 1; for(; ~p && st[p].nxt[c] == q; p = st[p].link) st[p].nxt[c] = clone; st[cur].link = st[q].link = clone; } }last = cur; } int nw = last; while(st[nw].la != Id) st[nw].la = Id, st[nw].vis ++, nw = st[nw].link; } int Need, ans[1010], Len; typedef map<int, int>::iterator it; void dfs(int u, int len){ if(st[u].vis <= Need)return; if(len == Len){ for(int i = 0; i < len; i ++) putchar(ans[i] + 'a');putchar('\n'); return; } for(int i = 0; i < 26; i ++) if(st[u].nxt.count(i)){ ans[len] = i, dfs(st[u].nxt[i], len + 1); } /*for(it i = st[u].nxt.begin(); i != st[u].nxt.end(); i ++) ans[len] = i->first, dfs(i->second, len + 1);*/ } void solve(){ if(Len == 0)puts("?"); else dfs(root, 0); } int main(){ int n; while(scanf("%d", &n) && n){ init(); for(int i = 1; i <= n; i ++){ scanf("%s", str + 1); int len = strlen(str + 1); last = 0; for(int j = 1; j <= len; j ++) Extend(str[j] - 'a', i); } st[0].vis = n; Need = n / 2; int ans = 0; for(int i = 1; i <= size; i ++) if(st[i].vis > Need) ans = max(ans, st[i].len); Len = ans; solve(); puts(""); } return 0; }
Ps:加强理解题意的能力!