Codeforces Round #526 (Div. 1) Solution

瞎扯

  首先吐槽一下這出題人有毒,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 A

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 B

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 C

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 D

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 E

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 }
Problem F
 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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章