這裏沒有翻譯c++
對於每行每列分別離散化,求出大於這個位置的數字的個數便可。數組
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(1005); int n, m, a[maxn][maxn], mx1[maxn][maxn], mx2[maxn][maxn], q[maxn], len; int main() { int i, j, p; scanf("%d%d", &n, &m); for (i = 1; i <= n; ++i) for (j = 1; j <= m; ++j) scanf("%d", &a[i][j]); for (i = 1; i <= n; ++i) { for (j = 1; j <= m; ++j) q[j] = a[i][j]; sort(q + 1, q + m + 1), len = unique(q + 1, q + m + 1) - q - 1; for (j = 1; j <= m; ++j) { p = lower_bound(q + 1, q + len + 1, a[i][j]) - q; mx1[i][j] = p, mx2[i][j] = len - p; } } for (i = 1; i <= m; ++i) { for (j = 1; j <= n; ++j) q[j] = a[j][i]; sort(q + 1, q + n + 1), len = unique(q + 1, q + n + 1) - q - 1; for (j = 1; j <= n; ++j) { p = lower_bound(q + 1, q + len + 1, a[j][i]) - q; mx1[j][i] = max(p, mx1[j][i]), mx2[j][i] = max(len - p, mx2[j][i]); } } for (i = 1; i <= n; ++i, puts("")) for (j = 1; j <= m; ++j) printf("%d ", mx1[i][j] + mx2[i][j]); return 0; }
每次選擇當前串的最長的 \(border\) 接上去便可spa
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(5e5 + 5); int len1, len2, nxt[maxn], cnt0, cnt, cnt1, mx; char s[maxn], t[maxn], ans[maxn]; int main() { int i, j, len = 0; scanf(" %s %s", s + 1, t + 1); len1 = strlen(s + 1), len2 = strlen(t + 1); for (i = 1; i <= len1; ++i) cnt0 += s[i] == '0'; for (i = 1; i <= len2; ++i) cnt += t[i] == '0'; if (len1 < len2 || cnt0 < cnt || len1 - cnt0 < len2 - cnt) return printf("%s\n", s + 1), 0; for (i = 2, j = 0; i <= len2; ++i) { while (j && t[j + 1] != t[i]) j = nxt[j]; if (t[j + 1] == t[i]) ++j; nxt[i] = j; } for (i = 1; i <= len2; ++i) ans[i] = t[i]; len = len2, cnt1 = len1 - cnt0, cnt0 -= cnt, mx = nxt[len2], cnt1 -= len2 - cnt; while (cnt0 && cnt1) { for (i = mx + 1; i <= len2 && cnt1 && cnt0; ++i) if (cnt0 - (t[i] == '0') >= 0 && cnt1 - (t[i] == '1') >= 0) ans[++len] = t[i], cnt0 -= t[i] == '0', cnt1 -= t[i] == '1'; } while (cnt0) ans[++len] = '0', --cnt0; while (cnt1) ans[++len] = '1', --cnt1; for (i = 1; i <= len1; ++i) putchar(ans[i]); return puts(""), 0; }
拆點,對於一個點 \(x\),拆成 \((x,1),(x,2),...,(x,d)\),在原圖中若是有邊 \(x,y\) 則連邊 \((x,i),(y,i\%d+1)\)。
能夠發現若是 \((x,i)\) 能到 \((x,j)\),那麼 \((x,j)\) 也必定能到達 \((x,i)\)。
因此 \((x,i),(x,j)\) 要麼在同一個強連通份量裏,要麼不在同一條直鏈上。
因此直接縮點 \(DP\) 便可。翻譯
// Memory limit exceeded on test 73 # include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(5e6 + 5); struct Edge { int to, next; }; int first[maxn], cnt, n, m, dd, id[100005][55], www[maxn], bf[maxn], val[maxn], num, ans; int dfn[maxn], low[maxn], idx, st[maxn], us[maxn], tot, tp, bel[maxn], f[maxn], d[maxn]; Edge edge[maxn]; char s[55]; vector <int> dag[maxn]; queue <int> Q; bitset <maxn> vis; inline void Add(int u, int v) { edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++; } void Tarjan(int u) { int e, v, r; dfn[u] = low[u] = ++idx, vis[u] = 1, st[++tp] = u; for (e = first[u]; ~e; e = edge[e].next) if (!dfn[v = edge[e].to]) Tarjan(v), low[u] = min(low[u], low[v]); else if (vis[v]) low[u] = min(low[u], dfn[v]); if (low[u] == dfn[u]) { ++num; do { vis[v = st[tp--]] = 0; if (www[v] && us[bf[v]] != num) us[bf[v]] = num, ++val[num]; bel[v] = num; } while (v ^ u); } } int main() { int i, j, u, v, e; memset(first, -1, sizeof(first)); scanf("%d%d%d", &n, &m, &dd); for (i = 1; i <= n; ++i) for (j = 1; j <= dd; ++j) id[i][j] = ++tot, bf[tot] = i; for (i = 1; i <= m; ++i) { scanf("%d%d", &u, &v); for (j = 1; j <= dd; ++j) Add(id[u][j], id[v][j % dd + 1]); } for (i = 1; i <= n; ++i) { scanf(" %s", s + 1); for (j = 1; j <= dd; ++j) www[id[i][j]] = s[j] == '1'; } for (i = 1; i <= tot; ++i) if (!dfn[i]) Tarjan(i); for (i = 1; i <= tot; ++i) for (e = first[i]; ~e; e = edge[e].next) if (bel[i] != bel[edge[e].to]) dag[bel[i]].push_back(bel[edge[e].to]), ++d[bel[edge[e].to]]; memset(f, -63, sizeof(f)), f[bel[1]] = val[bel[1]]; for (i = 1; i <= num; ++i) if (!d[i]) Q.push(i); while (!Q.empty()) { u = Q.front(), Q.pop(), ans = max(ans, f[u]); for (int t : dag[u]) { f[t] = max(f[t], f[u] + val[t]); if (!--d[t]) Q.push(t); } } printf("%d\n", ans); return 0; }
\(floyed\) 判環法,一我的 \(a\) 一次 \(1\) 步,另外一我的 \(b\) 一次 \(2\) 步。
設 \(a\) 走了 \(t+v\) 步,\(b\) 走了 \(2t+2v\) 步。
不難發現 \(c|(t+v)\),而 \(a\) 是一次 \(1\) 步,因此 \(a\) 必定沒有走完一個環,因此只要再次走 \(t\) 步就能夠恰好到了終點。
其它的點也是同樣。
總步驟 \(\le 3(c+t)\)。code
# include <bits/stdc++.h> using namespace std; typedef long long ll; char s[233]; inline int Read() { int x, i; scanf("%d", &x); for (i = 1; i <= x; ++i) scanf(" %s", s); return x; } int main() { while (true) { printf("next 0\n"), fflush(stdout), Read(); printf("next 0 1\n"), fflush(stdout); if (Read() == 2) break; } while (true) { printf("next 0 1 2 3 4 5 6 7 8 9\n"), fflush(stdout); if (Read() == 1) break; } printf("done"), fflush(stdout); return 0; }
不難發現每次加的一些 \(0\) 只要保留第一個就好了。
一操做很好作,直接扔掉前面的信息便可。
考慮二三操做,能夠想到用單調隊列來維護。
假設 \(x<y\),那麼一次三操做 \(v_x\) 變得小於 \(v_y\) 的條件顯然是
\(\frac{v_x-v_y}{x-y}>-s\),因此維護一個 \((v_x,x)\) 的斜率單調遞增的下凸殼便可。隊列
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(3e5 + 5); int n, m; ll Q[maxn], val[maxn], mov, hd, tl, ed, tagb, tags; inline ll Calc(int x) { return val[x] + tagb + tags * (Q[x] + mov - 1); } int main() { ll op, k, b, s; scanf("%d%d", &n, &m); Q[hd = tl = val[0] = 0] = 1, ed = n; while (m--) { scanf("%lld", &op); if (op <= 2) scanf("%lld", &k); else scanf("%lld%lld", &b, &s); if (op == 1) mov += k, ed += k, Q[hd = tl = 0] = 1 - mov, val[hd] = tagb = tags = 0; else if (op == 2) { while (hd < tl && 1.0 * (Calc(tl) - Calc(tl - 1)) / (Q[tl] - Q[tl - 1]) >= -1.0 * Calc(tl) / (ed + 1 - Q[tl] - mov)) --tl; Q[++tl] = ed + 1 - mov, val[tl] = -tagb - tags * ed, ed += k; } else tagb += b, tags += s; while (hd < tl && val[tl] + tags * (Q[tl] - Q[tl - 1]) - val[tl - 1] >= 0) --tl; printf("%lld %lld\n", Q[tl] + mov, Calc(tl)); } return 0; }
首先能夠以最後燒掉的點爲根,變成有根樹。
考慮一次 \(up~u\) 操做的影響,設原來的根爲 \(rt\),那麼會使得 \((u,rt)\) 這條鏈的順序變成 \(rt\) 燒到 \(u\) 而且是最後燒的鏈,其它點相對順序不變。
如今問題是怎麼統計每一個點在它以前的點的個數。
能夠把 \(up\) 操做當作是一種區間(鏈)覆蓋一個新的最大編號,而後換根。
那麼一個點的排名就變成了小於等於它的編號的點個數減去它祖先編號和它相同的點的個數。
這種染色問題能夠用 \(LCT\) 維護,\(up\) 就直接 \(access+makeroot\),同一個編號的點必定在一棵 \(Splay\) 中,直接覆蓋便可。
外加一個樹狀數組維護小於等於它的編號的點個數。get
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(4e5 + 5); int n, q, mx, cnt_col, d[maxn], cnt[maxn]; vector <int> edge[maxn]; int fa[maxn], ch[2][maxn], rev[maxn], col[maxn], sta[maxn], tp, size[maxn]; priority_queue <int> Q; inline void AddEdge(int u, int v) { edge[u].push_back(v), edge[v].push_back(u), ++d[u], ++d[v]; } inline void Add(int x, int v) { for (; x <= mx; x += x & -x) cnt[x] += v; } inline int Query(int x) { int ret = 0; for (; x; x ^= x & -x) ret += cnt[x]; return ret; } inline int Isroot(int x) { return (ch[0][fa[x]] ^ x) && (ch[1][fa[x]] ^ x); } inline int Son(int x) { return ch[1][fa[x]] == x; } inline void Update(int x) { size[x] = size[ch[0][x]] + size[ch[1][x]] + 1; } inline void Reverse(int x) { if (x) swap(ch[0][x], ch[1][x]), rev[x] ^= 1; } inline void Cover(int x, int v) { if (x) col[x] = v; } inline void Pushdown(int x) { if (rev[x]) rev[x] ^= 1, Reverse(ch[0][x]), Reverse(ch[1][x]); Cover(ch[0][x], col[x]), Cover(ch[1][x], col[x]); } inline void Rotate(int x) { int y = fa[x], z = fa[y], c = Son(x); if (!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z, ch[c][y] = ch[c ^ 1][x], fa[ch[c][y]] = y; ch[c ^ 1][x] = y, fa[y] = x, Update(y); } inline void Splay(int x) { int y; sta[tp = 1] = x; for (y = x; !Isroot(y); y = fa[y]) sta[++tp] = fa[y]; while (tp) Pushdown(sta[tp--]); for (y = fa[x]; !Isroot(x); Rotate(x), y = fa[x]) if (!Isroot(y)) (Son(x) ^ Son(y)) ? Rotate(x) : Rotate(y); Update(x); } inline void Access(int x) { int y; for (y = 0; x; y = x, x = fa[x]) { Splay(x), Add(col[x], -size[ch[0][x]] - 1); ch[1][x] = y, Update(x); } } inline void Makeroot(int x) { Access(x), Splay(x), Reverse(x), Cover(x, ++cnt_col), Add(col[x], size[x]); } inline int When(int x) { return Splay(x), Query(col[x]) - size[ch[0][x]]; } int main() { int i, u, v; char op[233]; scanf("%d%d", &n, &q), mx = n + q; for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u, v); for (i = 1; i <= n; ++i) if (d[i] == 1) Q.push(-i); while (!Q.empty()) { u = -Q.top(), Q.pop(), --d[u], Add(col[u] = ++cnt_col, 1); for (int to : edge[u]) if (--d[to] == 1) Q.push(-to); } for (u = 1; u <= n; ++u) for (int to : edge[u]) if (col[u] > col[to]) fa[to] = u; while (q--) { scanf(" %s%d", op + 1, &u); if (op[1] == 'u') Makeroot(u); else if (op[1] == 'w') printf("%d\n", When(u)); else scanf("%d", &v), printf("%d\n", When(u) < When(v) ? u : v); } return 0; }