從這裏開始
瞎扯
首先吐槽一下這出題人有毒,6道題,3道數據結構。再加上B題貪心,像我這種手速慢,智商不高,代碼還又臭又長的菜逼選手就很難受。
大概一堆選手40分鐘左右通過了我2小時過的所有題目,sad.....
Problem A The Fair Nut and the Best Path
題目大意
給定一棵樹,邊有邊權,點有點權,邊權是非正,點權非負,要求找到一條路徑,使得點權和邊權和最大。
我比較傻,去枚舉起點,然後就寫了正反兩個dp。
只用考慮經過當前點的路徑就可以dp了。
Code
1 /** 2 * Codeforces 3 * Problem#1083A 4 * Accepted 5 * Time: 343ms 6 * Memory: 46800k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <vector> 12 using namespace std; 13 #define ll long long 14 typedef bool boolean; 15 typedef pair<int, int> pii; 16 typedef pair<ll, int> par; 17 18 const int N = 3e5 + 5; 19 20 int n; 21 int w[N]; 22 par f[N], g[N]; 23 vector<pii> G[N]; 24 25 inline void init() { 26 scanf("%d", &n); 27 for (int i = 1; i <= n; i++) 28 scanf("%d", w + i); 29 for (int i = 1, u, v, w; i < n; i++) { 30 scanf("%d%d%d", &u, &v, &w); 31 G[u].push_back(pii(v, w)); 32 G[v].push_back(pii(u, w)); 33 } 34 } 35 36 void dfs1(int p, int fa) { 37 ll val; 38 f[p] = par(w[p], p); 39 g[p] = par(-1, 0); 40 for (auto e : G[p]) { 41 if (e.first == fa) 42 continue; 43 dfs1(e.first, p); 44 if ((val = f[e.first].first - e.second) < 0) 45 continue; 46 val += w[p]; 47 if (val > f[p].first) { 48 g[p] = f[p]; 49 f[p] = par(val, e.first); 50 } else if (val > g[p].first){ 51 g[p] = par(val, e.first); 52 } 53 } 54 // cerr << p << " " << f[p].first << " " << f[p].second << " " << g[p].first << '\n'; 55 } 56 57 ll ans = 0; 58 void dfs2(int p, int fa, ll fval) { 59 ans = max(ans, f[p].first); 60 ans = max(ans, fval); 61 ll best = f[p].first, dec = f[p].second, sec = g[p].first, val; 62 if (fval > best) 63 best = fval, dec = 0; 64 else if (fval > sec) 65 sec = fval; 66 for (auto e : G[p]) { 67 if (e.first == fa) 68 continue; 69 if (e.first == dec) 70 val = sec - e.second; 71 else 72 val = best - e.second; 73 if (val >= 0) 74 val += w[e.first]; 75 else 76 val = -1; 77 dfs2(e.first, p, val); 78 } 79 } 80 81 inline void solve() { 82 dfs1(1, 0); 83 dfs2(1, 0, -1); 84 printf("%I64d\n", ans); 85 } 86 87 int main() { 88 init(); 89 solve(); 90 return 0; 91 }
Problem B The Fair Nut and Strings
題目大意
要求在字典序大於等於$s$並且字典序小於等於$t$的長度爲$n$的ab串中選擇$m$個,並且將這些串插入一顆Trie中,Trie節點數最大,問最大的節點數減去1。
可以先把$s, t$的公共前綴部分截掉,這樣不會影響答案。
然後將$s, t$插入Trie樹。
還可以插入的貢獻爲$i$的串的數量是可以計算的。
對於每插入一個貢獻爲$i$的串,那麼還可以插入的貢獻爲$i - 1, i - 2, \dots, 1$的串的數量均會增加1,然後就可以貪心了。
Code
1 /** 2 * Codeforces 3 * Problem#1083B 4 * Accepted 5 * Time: 31ms 6 * Memory: 2900k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 using namespace std; 12 typedef bool boolean; 13 #define ll long long 14 15 const int N = 5e5 + 5; 16 17 int n, K; 18 ll ans; 19 int cnt[N]; 20 char s1[N], s2[N]; 21 22 inline void init() { 23 scanf("%d%d", &n, &K); 24 scanf("%s", s1 + 1); 25 scanf("%s", s2 + 1); 26 if (K == 1) { 27 printf("%d\n", n); 28 exit(0); 29 } 30 ans = n << 1; 31 int tp = 1; 32 while (tp <= n && s1[tp] == s2[tp]) 33 ans--, tp++; 34 for (int i = tp + 1; i <= n; i++) { 35 if (s1[i] == 'a') 36 cnt[i]++; 37 if (s2[i] == 'b') 38 cnt[i]++; 39 } 40 } 41 42 inline void solve() { 43 K -= 2; 44 int sum = 0, use, cur = 2; 45 while (K && cur <= n) { 46 use = min(K, cnt[cur] += sum); 47 ans += use * 1ll * (n - cur + 1); 48 K -= use, sum += use, cur++; 49 } 50 printf("%I64d\n", ans); 51 } 52 53 int main() { 54 init(); 55 solve(); 56 return 0; 57 }
Problem C Max Mex
題目大意
給定一棵樹,每個點有一個權值,任意兩點的權值不同,定義一條路徑的權值是它進過點權的mex,要求支持單點修改點權和查詢樹上權值最大的路徑。
問題可以轉化成求最大的$x$使得權值爲$0, 1, \dots, x - 1$的點都在一條路徑上。
用線段樹維護權值在$[l , r]$中的點的是否在一條路徑上以及最短的這樣的一條的路徑的端點(如果存在)。
很顯然信息是可以合併的(就是一個分類大討論)。
合併的時候只用考慮這4個端點是否在一條路徑上。這個只用考慮2次其中3個點就行了。
假如討論的是$(u, v, x)$,一種暴力的討論方式:
- $(u,v)$是一條連接祖先和後代的路徑
- $x$在較深點的子樹內
- $x$是較淺點的祖先
- $x$在路徑上
- $(u, v)$不是一條連接祖先和後代的路徑。
- $x$在端點的子樹內
- $x$在路徑上
Code
1 /** 2 * Codeforces 3 * Problem#1083C 4 * Accepted 5 * Time: 810ms 6 * Memory: 96700k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <vector> 13 using namespace std; 14 typedef bool boolean; 15 16 #define pii pair<int, int> 17 18 const int N = 2e5 + 5; 19 const int bzmax = 19; 20 21 typedef class SparseTable { 22 public: 23 int n; 24 int *in; 25 int log2[N << 1]; 26 pii f[bzmax][N << 1]; 27 28 SparseTable() { } 29 30 void init(int n, int* in, int* dep, int* seq) { 31 this->n = n; 32 this->in = in; 33 log2[0] = -1; 34 for (int i = 1; i <= n; i++) 35 log2[i] = log2[i >> 1] + 1; 36 37 for (int i = 1; i <= n; i++) 38 f[0][i] = pii(dep[seq[i]], seq[i]); 39 for (int j = 1; j < bzmax; j++) 40 for (int i = 1; i + (1 << j) <= n; i++) 41 f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]); 42 } 43 44 int query(int l, int r) { 45 int b = log2[r - l + 1]; 46 return min(f[b][l], f[b][r - (1 << b) + 1]).second; 47 } 48 49 int lca(int a, int b) { 50 int l = in[a], r = in[b]; 51 if (l > r) 52 swap(l, r); 53 return query(l, r); 54 } 55 }SparseTable; 56 57 typedef class PathData { 58 public: 59 int u, v; 60 boolean path; 61 62 PathData() : u(0), v(0), path(false) {} 63 PathData(int u, int v, boolean path) : u(u), v(v), path(path) { } 64 }PathData; 65 66 typedef class SegTreeNode { 67 public: 68 PathData pd; 69 SegTreeNode *l, *r; 70 71 void pushUp(); 72 }SegTreeNode; 73 74 SegTreeNode pool[N << 2]; 75 SegTreeNode *top = pool; 76 77 SegTreeNode* newnode() { 78 top->l = top->r = NULL; 79 return top++; 80 } 81 82 typedef class SegTree { 83 public: 84 SegTreeNode *rt; 85 86 SegTree() : rt(NULL) { } 87 SegTree(int n) { 88 build(rt, 0, n - 1); 89 } 90 91 void build(SegTreeNode*& p, int l, int r); 92 void modify(SegTreeNode* p, int l, int r, int idx, int val); 93 int query(); 94 }SegTree; 95 96 int n, m; 97 int dep[N]; 98 SegTree seg; 99 int p[N], q[N]; // q[p_i] = i 100 SparseTable st; 101 int seq[N << 1]; 102 vector<int> g[N]; 103 int in[N], out[N]; 104 105 inline void init() { 106 scanf("%d", &n); 107 for (int i = 1; i <= n; i++) { 108 scanf("%d", p + i); 109 q[p[i]] = i; 110 } 111 for (int i = 2, x; i <= n; i++) { 112 scanf("%d", &x); 113 g[x].push_back(i); 114 g[i].push_back(x); 115 } 116 } 117 118 int dfs_clock; 119 void dfs(int p, int fa) { 120 seq[++dfs_clock] = p; 121 in[p] = dfs_clock, dep[p] = dep[fa] + 1; 122 for (auto e : g[p]) { 123 if (e == fa) 124 continue; 125 dfs(e, p); 126 seq[++dfs_clock] = p; 127 } 128 out[p] = dfs_clock; 129 } 130 131 #define intree(father, son) (in[father] <= in[son] && out[father] >= out[son]) 132 133 PathData operator + (PathData path, int x) { 134 if (!path.path) 135 return PathData(); 136 int g = st.lca(path.u, path.v); 137 if (g == path.u || g == path.v) { 138 if (g == path.v) 139 swap(path.u, path.v); 140 if (intree(path.v, x)) 141 return PathData(x, g, true); 142 if (st.lca(g, x) == g && st.lca(path.v, x) == x) 143 return path; 144 int gx = st.lca(x, path.v); 145 if (st.lca(gx, g) == gx) 146 return PathData(path.u ^ path.v ^ g, x, true); 147 return PathData(); 148 } 149 if (intree(path.u, x)) 150 return PathData(x, path.v, true); 151 if (intree(path.v, x)) 152 return PathData(path.u, x, true); 153 if (st.lca(path.u, x) == x && st.lca(g, x) == g) 154 return path; 155 if (st.lca(path.v, x) == x && st.lca(g, x) == g) 156 return path; 157 return PathData(); 158 } 159 160 PathData operator + (PathData a, PathData b) { 161 if (!a.path || !b.path) 162 return PathData(); 163 return (a + b.u) + b.v; 164 } 165 166 void SegTreeNode :: pushUp() { 167 pd = l->pd + r->pd; 168 } 169 170 void SegTree :: build(SegTreeNode*& p, int l, int r) { 171 p = newnode(); 172 if (l == r) { 173 p->pd = PathData(q[l], q[l], true); 174 return; 175 } 176 int mid = (l + r) >> 1; 177 build(p->l, l, mid); 178 build(p->r, mid + 1, r); 179 p->pushUp(); 180 } 181 182 void SegTree :: modify(SegTreeNode* p, int l, int r, int idx, int val) { 183 if (l == r) { 184 p->pd = PathData(val, val, true); 185 return; 186 } 187 int mid = (l + r) >> 1; 188 if (idx <= mid) 189 modify(p->l, l, mid, idx, val); 190 else 191 modify(p->r, mid + 1, r, idx, val); 192 p->pushUp(); 193 } 194 195 int SegTree :: query() { 196 SegTreeNode *p = rt; 197 int l = 0, r = n - 1, mid; 198 PathData pd(q[0], q[0], true), tmp; 199 while (l < r) { 200 mid = (l + r) >> 1; 201 tmp = pd + p->l->pd; 202 // cerr << pd.u << " " << pd.v << " " << p->l->pd.u << " " << p->l->pd.v << ' ' << tmp.u << " " << tmp.v << '\n'; 203 if (tmp.path) 204 p = p->r, pd = tmp, l = mid + 1; 205 else 206 p = p->l, r = mid; 207 } 208 tmp = pd + p->pd; 209 if (tmp.path) 210 return l + 1; 211 return l; 212 } 213 214 inline void solve() { 215 dfs(1, 0); 216 st.init(dfs_clock, in, dep, seq); 217 seg = SegTree(n); 218 219 scanf("%d", &m); 220 int opt, x, y; 221 while (m--) { 222 scanf("%d", &opt); 223 if (opt == 2) { 224 printf("%d\n", seg.query()); 225 } else { 226 scanf("%d%d", &x, &y); 227 // q_{p_x} = x, q_{p_y} = y -> q_{p_x} = y, q_{p_y} = x 228 seg.modify(seg.rt, 0, n - 1, p[x], y); 229 seg.modify(seg.rt, 0, n - 1, p[y], x); 230 swap(p[x], p[y]); 231 swap(q[p[x]], q[p[y]]); 232 } 233 } 234 } 235 236 int main() { 237 init(); 238 solve(); 239 return 0; 240 }
Problem D The Fair Nut's getting crazy
題目大意
給定一個序列$a$,詢問兩個相交但互相不包含並且交集中的數在兩個區間中分別只出現1次的區間對的數量。
這難度真假。。。居然有3400。。
考慮枚舉交的右端點$i$,對於一個交的左端點$j$,設$l = \max_{k = j}^{i} \{pre_k\}, r = \min_{k = j}^{i}\{suf_k\}$。
那麼當合法的時候,對答案的貢獻爲$(j - l - 1)(r - i - 1)$。
化簡一下式子就可以線段樹維護對於每一個左端點相應的量。
Code
1 /** 2 * Codeforces 3 * Problem#1083 4 * Accepted 5 * Time: 358ms 6 * Memory: 21600k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <map> 12 using namespace std; 13 typedef bool boolean; 14 15 #define ll long long 16 17 const int Mod = 1e9 + 7; 18 19 int add(int a, int b) { 20 return ((a += b) >= Mod) ? (a - Mod) : (a); 21 } 22 23 int sub(int a, int b) { 24 return ((a -= b) < 0) ? (a + Mod) : (a); 25 } 26 27 int mul(int a, int b) { 28 return a * 1ll * b % Mod; 29 } 30 31 int sum(int n) { 32 return (n * 1ll * (n + 1) >> 1) % Mod; 33 } 34 35 int sum(int l, int r) { 36 return sub(sum(r), sum(l - 1)); 37 } 38 39 typedef class Data { 40 public: 41 int suml, sumr; 42 int sumlr, sumcof; 43 int sumrj; 44 45 Data() : suml(0), sumr(0), sumlr(0), sumcof(0), sumrj(0) { } 46 Data(int suml, int sumr, int sumlr, int sumcof, int sumrj) : suml(suml), sumr(sumr), sumlr(sumlr), sumcof(sumcof), sumrj(sumrj) { } 47 48 void update_l(int vl, int L, int R) { 49 sumlr = mul(vl, sumr); 50 suml = mul(R - L + 1, vl); 51 sumcof = sub(sum(L - 1, R - 1), suml); 52 } 53 54 void update_r(int vr, int L, int R) { 55 sumlr = mul(suml, vr); 56 sumr = mul(R - L + 1, vr); 57 sumrj = mul(vr, sum(L - 1, R - 1)); 58 } 59 60 Data operator + (Data b) { 61 Data rt; 62 rt.suml = add(suml, b.suml); 63 rt.sumr = add(sumr, b.sumr); 64 rt.sumlr = add(sumlr, b.sumlr); 65 rt.sumcof = add(sumcof, b.sumcof); 66 rt.sumrj = add(sumrj, b.sumrj); 67 return rt; 68 } 69 }Data; 70 71 typedef class SegTreeNode { 72 public: 73 Data d; 74 int mx_l; 75 int tgl, tgr; 76 SegTreeNode *l, *r; 77 78 SegTreeNode() : d(Data()), mx_l(-Mod), tgl(-1), tgr(-1), l(NULL), r(NULL) { } 79 80 void update(int dl, int dr, int L, int R) { 81 if (dl != -1) { 82 d.update_l(dl, L, R); 83 mx_l = dl - R; 84 tgl = dl; 85 } 86 if (dr != -1) { 87 d.update_r(dr, L, R); 88 tgr = dr; 89 } 90 } 91 92 void pushDown(int L, int R) { 93 int mid = (L + R) >> 1; 94 l->update(tgl, tgr, L, mid); 95 r->update(tgl, tgr, mid + 1, R); 96 tgl = tgr = -1; 97 } 98 99 void pushUp() { 100 d = l->d + r->d; 101 mx_l = max(l->mx_l, r->mx_l); 102 } 103 }SegTreeNode; 104 105 const int N = 1e5 + 5; 106 107 SegTreeNode pool[N << 2]; 108 SegTreeNode *top = pool; 109 110 SegTreeNode* newnode() { 111 return top++; 112 } 113 114 typedef class SegTree { 115 public: 116 SegTreeNode* rt; 117 118 SegTree() : rt(NULL) { } 119 SegTree(int n) { 120 build(rt, 1, n); 121 } 122 123 void build(SegTreeNode*& p, int l, int r) { 124 p = newnode(); 125 if (l == r) 126 return ; 127 int mid = (l + r) >> 1; 128 build(p->l, l, mid); 129 build(p->r, mid + 1, r); 130 } 131 132 void update(SegTreeNode* p, int l, int r, int ql, int qr, int vl, int vr) { 133 if (l == ql && r == qr) { 134 p->update(vl, vr, l, r); 135 return; 136 } 137 if (p->tgl != -1 || p->tgr != -1) 138 p->pushDown(l, r); 139 int mid = (l + r) >> 1; 140 if (qr <= mid) 141 update(p->l, l, mid, ql, qr, vl, vr); 142 else if (ql > mid) 143 update(p->r, mid + 1, r, ql, qr, vl, vr); 144 else { 145 update(p->l, l, mid, ql, mid, vl, vr); 146 update(p->r, mid + 1, r, mid + 1, qr, vl, vr); 147 } 148 p->pushUp(); 149 } 150 151 Data query(SegTreeNode* p, int l, int r, int ql, int qr) { 152 if (l == ql && r == qr) 153 return p->d; 154 if (p->tgl != -1 || p->tgr != -1) 155 p->pushDown(l, r); 156 int mid = (l + r) >> 1; 157 if (qr <= mid) 158 return query(p->l, l, mid, ql, qr); 159 if (ql > mid) 160 return query(p->r, mid + 1, r, ql, qr); 161 Data _ = query(p->l, l, mid, ql, mid); 162 Data __ = query(p->r, mid + 1, r, mid + 1, qr); 163 return _ + __; 164 } 165 166 int query(SegTreeNode* p, int l, int r) { 167 if (l == r) 168 return (p->mx_l >= 0) ? (l) : (l - 1); 169 if (p->tgl != -1 || p->tgr != -1) 170 p->pushDown(l, r); 171 int mid = (l + r) >> 1; 172 if (p->r->mx_l >= 0) 173 return query(p->r, mid + 1, r); 174 return query(p->l, l, mid); 175 } 176 }SegTree; 177 178 typedef pair<int, int> par; 179 180 int n; 181 int a[N]; 182 SegTree st; 183 int pre[N], suf[N]; 184 map<int, int> head; 185 int top_l = 0, top_r = 0; 186 par stack_l[N], stack_r[N]; 187 188 inline void init() { 189 scanf("%d", &n); 190 for (int i = 1; i <= n; i++) 191 scanf("%d", a + i); 192 for (int i = 1; i <= n; i++) { 193 pre[i] = head[a[i]]; 194 head[a[i]] = i; 195 } 196 head.clear(); 197 for (int i = n; i; i--) { 198 if (!head.count(a[i])) 199 suf[i] = n + 1; 200 else 201 suf[i] = head[a[i]]; 202 head[a[i]] = i; 203 } 204 head.clear(); 205 } 206 207 int ans = 0; 208 inline void solve() { 209 st = SegTree(n); 210 stack_l[top_l] = par(Mod, 0); 211 stack_r[top_r] = par(-Mod, 0); 212 for (int i = 1, l, r, mid, border; i <= n; i++) { 213 // cerr << "R[2, 2] = " << st.rt->l->r->d.sumr << '\n'; 214 while (stack_l[top_l].first <= pre[i]) 215 top_l--; 216 st.update(st.rt, 1, n, stack_l[top_l].second + 1, i, pre[i], -1); 217 stack_l[++top_l] = par(pre[i], i); 218 while (stack_r[top_r].first >= suf[i]) 219 top_r--; 220 st.update(st.rt, 1, n, stack_r[top_r].second + 1, i, -1, suf[i]); 221 stack_r[++top_r] = par(suf[i], i); 222 223 l = 1, r = top_r; 224 while (l <= r) { 225 mid = (l + r) >> 1; 226 if (stack_r[mid].first > i) 227 r = mid - 1; 228 else 229 l = mid + 1; 230 } 231 border = stack_r[r].second + 1; 232 border = max(border, st.query(st.rt, 1, n) + 1); 233 234 Data d = st.query(st.rt, 1, n, border, i); 235 236 ans = sub(ans, d.sumlr); 237 ans = add(ans, d.sumrj); 238 ans = sub(ans, mul(i + 1, d.sumcof)); 239 // cerr << i << " " << ans << " " << d.sumlr << " " << d.sumrj << " " << d.sumcof << " " << border << " " << d.suml << " " << d.sumr << '\n'; 240 } 241 printf("%d\n", ans); 242 } 243 244 int main() { 245 #ifdef debug 246 freopen("input.txt", "r", stdin); 247 #endif 248 init(); 249 solve(); 250 return 0; 251 }
Problem E The Fair Nut and Rectangles
題目大意
(原題題意真簡潔,不需要大意)
按$x_i$排序,顯然可以斜率優化。
Code
1 /** 2 * Codeforces 3 * Problem#1083E 4 * Accepted 5 * Time: 655ms 6 * Memory: 27400k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #ifndef WIN32 13 #define Auto "%lld" 14 #else 15 #define Auto "%I64d" 16 #endif 17 using namespace std; 18 typedef bool boolean; 19 20 #define ll long long 21 22 typedef class Item { 23 public: 24 int x, y; 25 ll cost; 26 27 void read() { 28 scanf("%d%d"Auto, &x, &y, &cost); 29 } 30 31 boolean operator < (Item b) const { 32 return x < b.x; 33 } 34 }Item; 35 36 int n; 37 ll *f; 38 Item *a; 39 40 inline void init() { 41 scanf("%d", &n); 42 f = new ll[(n + 1)]; 43 a = new Item[(n + 1)]; 44 for (int i = 1; i <= n; i++) 45 a[i].read(); 46 a[0].x = 0; 47 } 48 49 double slope(int u, int v) { 50 return (f[v] - f[u]) * 1.0 / (a[v].x - a[u].x); 51 } 52 53 ll value(int x, int k) { 54 return f[x] - k * 1ll * a[x].x; 55 } 56 57 int st = 1, ed = 0; 58 int *sta; 59 inline void solve() { 60 ll ans = 0; 61 sort(a + 1, a + n + 1); 62 sta = new int[(n + 5)]; 63 sta[++ed] = 0; 64 f[0] = 0; 65 for (int i = 1; i <= n; i++) { 66 while (st < ed && value(sta[st], a[i].y) < value(sta[st + 1], a[i].y)) 67 st++; 68 f[i] = value(sta[st], a[i].y) + a[i].x * 1ll * a[i].y - a[i].cost; 69 while (st < ed && slope(sta[ed - 1], sta[ed]) <= slope(sta[ed], i)) 70 ed--; 71 sta[++ed] = i; 72 ans = max(f[i], ans); 73 } 74 printf(Auto"\n", ans); 75 } 76 77 int main() { 78 init(); 79 solve(); 80 return 0; 81 }
Problem F The Fair Nut and Amusing Xor
題目大意
給定兩個長度爲$n$的數組$a, b$和$k$,定義它們之間的相似度爲最少的操作數使得$a,b$一樣。每次操作可以選擇$a$的一個長度爲$k$的一個子段,將其中的所有數異或上$x$($x$可以自選)。
要求支持單點修改和查詢相似度。
先將$a$的每一位異或上$b$得到的數組記爲$c$,然後差分$c$,顯然對於一次操作,$c$上對$k$取模不同餘的兩個位置相互獨立。
然後問題可以轉化成$k = 2$的情況。再對$c$求前綴異或和(對每個對$k$取模同餘的位置分開做),這樣每次修改只會影響1位了,現在只用快速維護$c$的前綴和然後統計有多少位爲0,以及判斷是否合法(最後$k - 1$位是否是0,因爲不能在這些地方修改)。
- $k > \sqrt{n}$,直接暴力。
- $k \leqslant \sqrt{n}$,對每一部分分塊維護。顯然標記可以合併和下放,也可以快速查詢0的個數。
Code
1 /** 2 * Codeforces 3 * Problem#1083F 4 * Accepted 5 * Time: 2979ms 6 * Memory: 42100k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <vector> 12 #include <cmath> 13 using namespace std; 14 typedef bool boolean; 15 16 const int V = 1 << 14; 17 18 template <typename T> 19 void pfill(T* pst, const T* ped, T val) { 20 for ( ; pst != ped; *(pst++) = val); 21 } 22 23 typedef class Chunk { 24 private: 25 boolean inited; 26 public: 27 int sz, tg; 28 int *a, *b; // array, bucket 29 30 Chunk() : inited(false), sz(0), tg(0), a(NULL), b(NULL) { } 31 32 boolean append(int); 33 void modify(int, int); 34 35 void push_down() { 36 if (!tg) 37 return; 38 for (int i = 0; i < sz; i++) 39 b[a[i]] = 0; 40 for (int i = 0; i < sz; i++) 41 b[a[i] ^= tg]++; 42 tg = 0; 43 } 44 45 int back() { 46 return (*this) [sz - 1]; 47 } 48 49 int operator [] (int p) { 50 return a[p] ^ tg; 51 } 52 53 int operator () (int p) { 54 return b[p ^ tg]; 55 } 56 }Chunk; 57 58 #ifndef local 59 FILE* fin = stdin; 60 #else 61 FILE* fin = fopen("input.txt", "r"); 62 #endif 63 64 int n, len, q; 65 int *a, *b, *c; 66 67 int lim_sz; 68 int cnt_zero, cnt_non_zero; // at end 69 70 int *end_pos; 71 vector<Chunk> *ch; 72 73 inline void init() { 74 fscanf(fin, "%d%d%d", &n, &len, &q); 75 a = new int[(n + 1)]; 76 b = new int[(n + 1)]; 77 c = new int[(n + 1)]; 78 for (int i = 0; i < n; i++) { 79 fscanf(fin, "%d", a + i); 80 } 81 for (int i = 0; i < n; i++) { 82 fscanf(fin, "%d", b + i); 83 c[i] = a[i] ^ b[i]; 84 } 85 for (int i = n - 1; i; i--) 86 c[i] = c[i] ^ c[i - 1]; 87 } 88 89 boolean Chunk :: append(int x) { 90 if (!inited) { 91 a = new int[lim_sz]; 92 b = new int[V]; 93 pfill(b, b + V, 0); 94 inited = true; 95 } 96 if (sz == lim_sz) 97 return false; 98 a[sz++] = x; 99 b[x]++; 100 return true; 101 } 102 103 void Chunk :: modify(int idx, int val) { 104 if (!idx) 105 tg ^= val; 106 else { 107 push_down(); 108 for (int i = idx; i < sz; i++) { 109 b[a[i]]--; 110 b[a[i] ^= val]++; 111 } 112 } 113 } 114 115 void put_ans() { 116 printf("%d\n", (cnt_non_zero) ? (-1) : (n - cnt_zero)); 117 } 118 119 #define upd(_cid, _pid, _idx, _v) { \ 120 cnt_zero -= ch[_cid][_pid](0); \ 121 ch[_cid][_pid].modify(_idx, _v); \ 122 cnt_zero += ch[_cid][_pid](0); \ 123 } 124 125 char str[5]; 126 namespace small { 127 128 inline void solve() { 129 end_pos = new int[(len + 1)]; 130 ch = new vector<Chunk>[(len + 1)]; 131 for (int i = 0; i < len; i++) // if len = n 132 ch[i].push_back(Chunk()); 133 lim_sz = (int) sqrt(n + 0.5); 134 for (int i = 0, cid = 0, x; i < n; i++) { 135 x = ((i >= len) ? (ch[cid].back().back()) : (0)) ^ c[i]; 136 if (!ch[cid].back().append(x)) { 137 ch[cid].push_back(Chunk()); 138 ch[cid].back().append(x); 139 } 140 ++cid; 141 if (cid == len) 142 cid = 0; 143 } 144 145 int exception = n % len; 146 for (int i = 0; i < len; i++) { 147 for (auto& b : ch[i]) { 148 cnt_zero += b(0); 149 } 150 if (i ^ exception) 151 cnt_non_zero += !!ch[i].back().back(); 152 } 153 put_ans(); 154 155 int p, v, cid, pid, idx; 156 while (q--) { 157 fscanf(fin, "%s%d%d", str, &p, &v), p--; 158 int old_c = a[p] ^ b[p]; 159 (str[0] == 'a') ? (a[p] = v) : (b[p] = v); 160 int ncp = a[p] ^ b[p]; 161 162 v = old_c ^ ncp; 163 c[p] ^= v; 164 cid = p % len; 165 pid = p / len / lim_sz; 166 idx = (p / len) % lim_sz; 167 168 if (cid != exception) 169 cnt_non_zero -= !!ch[cid].back().back(); 170 upd(cid, pid, idx, v); 171 for (int i = pid + 1; i < (signed) ch[cid].size(); i++) 172 upd(cid, i, 0, v); 173 if (cid != exception) 174 cnt_non_zero += !!ch[cid].back().back(); 175 176 if (p + 1 < n) { 177 c[p + 1] ^= v; 178 cid = (p + 1) % len; 179 pid = (p + 1) / len / lim_sz; 180 idx = ((p + 1) / len) % lim_sz; 181 182 if (cid != exception) 183 cnt_non_zero -= !!ch[cid].back().back(); 184 upd(cid, pid, idx, v); 185 for (int i = pid + 1; i < (signed) ch[cid].size(); i++) 186 upd(cid, i, 0, v); 187 if (cid != exception) 188 cnt_non_zero += !!ch[cid].back().back(); 189 } 190 191 put_ans(); 192 } 193 } 194 195 } 196 197 namespace large { 198 199 inline void solve() { 200 201 for (int i = len; i < n; i++) 202 c[i] ^= c[i - len]; 203 for (int i = 0; i < n; i++) 204 cnt_zero += !c[i]; 205 for (int i = n - len + 1; i < n; i++) 206 cnt_non_zero += !!c[i]; 207 208 int exception = n % len; 209 put_ans(); 210 211 int p, v, cid, lst; 212 while (q--) { 213 fscanf(fin, "%s%d%d", str, &p, &v), p--; 214 int old_c = a[p] ^ b[p]; 215 (str[0] == 'a') ? (a[p] = v) : (b[p] = v); 216 int ncp = a[p] ^ b[p]; 217 218 v = old_c ^ ncp; 219 cid = p % len; 220 lst = (n - cid) / len * len + cid; 221 // cerr << p << ' ' << lst << '\n'; 222 223 if (cid != exception) 224 cnt_non_zero -= !!c[lst]; 225 for (int i = p; i < n; i += len) { 226 cnt_zero -= !c[i]; 227 c[i] ^= v; 228 cnt_zero += !c[i]; 229 } 230 if (cid != exception) 231 cnt_non_zero += !!c[lst]; 232 233 if (p + 1 < n) { 234 cid = (p + 1) % len; 235 lst = (n - cid) / len * len + cid; 236 237 if (cid != exception) 238 cnt_non_zero -= !!c[lst]; 239 for (int i = p + 1; i < n; i += len) { 240 cnt_zero -= !c[i]; 241 c[i] ^= v; 242 cnt_zero += !c[i]; 243 } 244 if (cid != exception) 245 cnt_non_zero += !!c[lst]; 246 } 247 248 put_ans(); 249 } 250 } 251 252 } 253 254 inline void solve() { 255 int lim = sqrt(n + 0.5); 256 if (len <= lim) 257 small :: solve(); 258 else 259 large :: solve(); 260 } 261 262 int main() { 263 init(); 264 solve(); 265 return 0; 266 }
1 /** 2 * Codeforces 3 * Problem#1025D 4 * Accepted 5 * Time: 31ms 6 * Memory: 100k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 1e5 + 5;