-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
329 lines (233 loc) · 166 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[CF题解(杂)]]></title>
<url>%2F2018%2F07%2F29%2FCF-other%2F</url>
<content type="text"><![CDATA[题目传送门 E. Store二维数据结构树套树即可也可以分治一维,另一维用数据结构维护123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;template<class T> struct node { T val; int cl, cr; void clear() { val = 0; cl = cr = 0; }};template<class T> struct SegBit { node<T> f[maxn * 100]; int limx, limy, tot; void init(int x, int y) { tot = limx = x; limy = y; for(int i = 1; i <= limx; i++) f[i].clear(); } void update(int t, int l, int r, int x, T v) { if(l == r) { f[t].val += v; // 单点更新 return; } int mid = (l + r) >> 1; if(x <= mid) { if(!f[t].cl) { f[t].cl = ++tot; f[tot].clear(); } update(f[t].cl, l, mid, x, v); } else { if(!f[t].cr) { f[t].cr = ++tot; f[tot].clear(); } update(f[t].cr, mid + 1, r, x, v); } f[t].val = 0; if(f[t].cl) f[t].val += f[f[t].cl].val; if(f[t].cr) f[t].val += f[f[t].cr].val; } T query(int t, int l, int r, int ll, int rr) { if(ll <= l && r <= rr) return f[t].val; int mid = (l + r) >> 1; T res = 0; if(f[t].cl && ll <= mid) res += query(f[t].cl, l, mid, ll, rr); if(f[t].cr && rr > mid) res += query(f[t].cr, mid + 1, r, ll, rr); return res; } void update(int x, int y, int v) { for(; x <= limx; x += (x & -x)) update(x, 1, limy, y, v); } T query(int x, int y1, int y2) { T res = 0; for(; x > 0; x -= (x & -x)) res += query(x, 1, limy, y1, y2); return res; } T query(int x1, int x2, int y1, int y2) { return query(x2, y1, y2) - query(x1 - 1, y1, y2); }};struct fnode { int op, x1, x2, y1, y2;};vector<P> id[maxn];vector<fnode> fq[maxn];int ans[maxn];SegBit<int> S;int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int x, y, z, n, m, k, i, a, b, c; int xl, xr, yl, yr, zl, zr; scanf("%d%d%d%d%d%d", &x, &y, &z, &n, &m, &k); xl = x; xr = 0; yl = y; yr = 0; zl = z; zr = 0; for(i = 0; i < n; i++) { scanf("%d%d%d", &a, &b, &c); xl = min(xl, a); xr = max(xr, a); yl = min(yl, b); yr = max(yr, b); zl = min(zl, c); zr = max(zr, c); } for(i = 0; i < m; i++) { scanf("%d%d%d", &a, &b, &c); if(xl <= a && a <= xr && yl <= b && b <= yr && zl <= c && c <= zr) { puts("INCORRECT"); return 0; } id[a].push_back(P(b, c)); } puts("CORRECT"); int fxl, fxr, fyl, fyr, fzl, fzr; for(i = 1; i <= k; i++) { scanf("%d%d%d", &a, &b, &c); if(xl <= a && a <= xr && yl <= b && b <= yr && zl <= c && c <= zr) ans[i] = -1; else { fxl = min(xl, a); fxr = max(xr, a); fyl = min(yl, b); fyr = max(yr, b); fzl = min(zl, c); fzr = max(zr, c); fq[fxl - 1].push_back(fnode{-i, fyl, fyr, fzl, fzr}); fq[fxr].push_back(fnode{i, fyl, fyr, fzl, fzr}); } } S.init(y, z); for(i = 1;i <= x; i++) { for(auto e:id[i]) S.update(e.fi, e.se, 1); for(auto e:fq[i]) ans[abs(e.op)] += (e.op > 0 ? 1 : -1) * S.query(e.x1, e.x2, e.y1, e.y2); } for(i = 1;i <= k; i++) { if(ans[i] == -1) puts("OPEN"); else if(ans[i] == 0) puts("UNKNOWN"); else puts("CLOSED"); } return 0;} 题目传送门 G. Allowed Letters枚举当前位置的字符是什么利用二维前缀和和$bitmarks$就可以很快的确定当前位置能不能填这个值 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;char s[maxn], fs[55], ans[maxn];int mk[maxn], cnt[64], dm[64];int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, i, j, k, x; scanf("%s", s + 1); n = strlen(s + 1); for(i = 1; i <= n; i++) cnt[1 << (s[i] - 'a')]++; for(i = 1; i <= n; i++) mk[i] = 63; scanf("%d", &m); while(m--) { scanf("%d %s", &i, fs); k = strlen(fs); for(x = j = 0; j < k; j++) x |= 1 << (fs[j] - 'a'); mk[i] = x; } for(i = 1; i <= n; i++) dm[mk[i]]++; for(i = 0; i < 6; i++) { for(j = 0; j < 64; j++) { if((j >> i) & 1) { cnt[j] += cnt[j ^ (1 << i)]; dm[j] += dm[j ^ (1 << i)]; } } } for(i = 1; i <= n; i++) { x = mk[i]; for(k = 0; k < 64; k++) { if((k & x) == x) dm[k]--; } for(j = 0; j < 6; j++) { if((x >> j) & 1) { if(!cnt[1 << j]) continue; for(k = 0; k < 64; k++) { if((k >> j) & 1) cnt[k]--; } bool fg = 0; for(k = 0; k < 64; k++) fg |= dm[k] > cnt[k]; if(!fg) { ans[i] = 'a' + j; break; } for(k = 1; k < 64; k++) { if((k >> j) & 1) cnt[k]++; } } } if(j == 6) return puts("Impossible"), 0; } ans[n + 1] = 0; printf("%s\n", ans + 1); return 0;} 题目传送门 D. Cycles in product$dp$维护两棵树上所有长度为$i$的环的路径个数即可123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 998244353;const int maxn = 4005;void add(int &x, int y) { x += y; if(x >= mod) x -= mod;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}vector<int> g[maxn];int f[maxn][40], pre[maxn][40], d[40], w[40], k;int f1[40], f2[40], c[80][80];void merge(int p[], int q[]) { for(int i = 1;i <= k; i++) { for(int j = 0;j < i; j++) add(p[i], mul(p[i - j - 1], q[j])); }}void split(int p[], int q[]) { for(int i = k;i > 0; i--) { for(int j = 0;j < i; j++) add(p[i], mod - mul(p[i - j - 1], q[j])); }}void pdfs(int u, int fa) { memset(f[u], 0, sizeof(f[u])); f[u][0] = 1; for(auto v : g[u]) { if(v == fa) continue; pdfs(v, u); } memset(d, 0, sizeof(d)); for(auto v : g[u]) { if(v == fa) continue; for(int i = 0;i < k; i++) add(d[i], f[v][i]); } merge(f[u], d);}void dfs(int u, int fa) { memcpy(d, pre[u], sizeof(d)); for(auto v : g[u]) { if(v == fa) continue; for(int i = 0;i < k; i++) add(d[i], f[v][i]); } memset(w, 0, sizeof(w)); w[0] = 1; merge(w, d); for(int i = 0; i <= k; i++) add(f1[i], w[i]); for(auto v : g[u]) { if(v == fa) continue; for(int i = 0;i < k; i++) add(d[i], mod - f[v][i]); memset(pre[v], 0, sizeof(pre[v])); pre[v][0] = 1; merge(pre[v], d); for(int i = 0;i < k; i++) add(d[i], f[v][i]); } for(auto v : g[u]) { if(v == fa) continue; dfs(v, u); }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n1, n2, i, u, v, ans = 0; for(i = 0;i < 80; i++) { c[i][0] = 1; for(v = 1;v <= i; v++) { c[i][v] = c[i - 1][v - 1]; add(c[i][v], c[i - 1][v]); } } scanf("%d%d%d", &n1, &n2, &k); if(k & 1) return puts("0"), 0; k >>= 1; for(i = 1; i < n1; i++) { scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } pdfs(1, 0); dfs(1, 0); memcpy(f2, f1, sizeof(f1)); memset(f1, 0, sizeof(f1)); memset(pre[1], 0, sizeof(pre[1])); for(i = 1;i <= n1; i++) g[i].clear(); for(i = 1; i < n2; i++) { scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } pdfs(1, 0); dfs(1, 0); for(i = 0;i <= k; i++) add(ans, mul(c[k * 2][i * 2], mul(f1[i], f2[k - i]))); printf("%d\n", ans); return 0;} 题目传送门 E. Good Subsegments一个好的区间一定是等价于满足$max - min = r - l$离线询问,从$1$枚举到$n$利用栈维护出当前值作为最大值或最小值的区间长度线段树维护$l - i + max - min$的值每次加上值为$0$的数的数量因为这个值一定是$>= 0$的,所以等价于维护区间最小值就可以了123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 120005;struct node { int ft, val, fmin, cnt; LL sum; void add(node &l, node &r) { sum = l.sum + r.sum; fmin = min(l.fmin, r.fmin); cnt = 0; if(fmin == l.fmin) cnt += l.cnt; if(fmin == r.fmin) cnt += r.cnt; } void down(node &l, node &r) { if(val) { l.add(val); r.add(val); val = 0; } if(ft) { if(fmin == l.fmin) l.addt(ft); if(fmin == r.fmin) r.addt(ft); ft = 0; } } void add(int x) { val += x; fmin += x; } void addt(int x) { ft += x; sum += 1LL * x * cnt; }} f[maxn << 2];int a[maxn], pmax[maxn], pmin[maxn];LL ans[maxn];vector<P> fq[maxn];void build(int t, int l, int r) { if(l == r) { f[t].fmin = l; f[t].cnt = 1; return; } int mid = (l + r) >> 1; build(t << 1, l, mid); build(t << 1 | 1, mid + 1, r); f[t].add(f[t << 1], f[t << 1 | 1]);}void update(int t, int l, int r, int ll, int rr, int x) { if(ll <= l && r <= rr) { f[t].add(x); return; } int mid = (l + r) >> 1; f[t].down(f[t << 1], f[t << 1 | 1]); if(ll <= mid) update(t << 1, l, mid, ll, rr, x); if(rr > mid) update(t << 1 | 1, mid + 1, r, ll, rr, x); f[t].add(f[t << 1], f[t << 1 | 1]);}LL query(int t, int l, int r, int ll) { if(l >= ll) return f[t].sum; int mid = (l + r) >> 1; f[t].down(f[t << 1], f[t << 1 | 1]); LL res = query(t << 1 | 1, mid + 1, r, ll); if(ll <= mid) res += query(t << 1, l, mid, ll); f[t].add(f[t << 1], f[t << 1 | 1]); return res;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, q, i, x, y; scanf("%d", &n); for(i = 1;i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); scanf("%d", &q); for(i = 1;i <= q; i++) { scanf("%d%d", &x, &y); fq[y].push_back(P(x, i)); } x = y = 0; for(i = 1;i <= n; i++) { f[1].add(-1); while(x && a[pmax[x]] < a[i]) { update(1, 1, n, pmax[x - 1] + 1, pmax[x], a[i] - a[pmax[x]]); x--; } pmax[++x] = i; while(y && a[pmin[y]] > a[i]) { update(1, 1, n, pmin[y - 1] + 1, pmin[y], a[pmin[y]] - a[i]); y--; } pmin[++y] = i; f[1].addt(1); for(auto e:fq[i]) ans[e.se] = query(1, 1, n, e.fi); } for(i = 1;i <= q; i++) printf("%lld\n", ans[i]); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#497(Div. 1)]]></title>
<url>%2F2018%2F07%2F29%2FCF-497%2F</url>
<content type="text"><![CDATA[题目传送门 C. Guess two numbers考虑类似二分的方法因为可行解区域是一个$L$型按面积考虑二分位置即可1234567891011121314151617181920212223242526272829303132333435363738394041424344#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int query(LL x, LL y) { printf("%lld %lld\n", x, y); fflush(stdout); int u; scanf("%d", &u); if(u == 0) exit(0); return u;}void solve(LL xl, LL xm, LL xr, LL yl, LL ym, LL yr) { if(xm <= xl) xm = xr, yr = ym; if(ym <= yl) ym = yr, xr = xm; long double sa = (long double)(xm - xl) * (ym - yl); long double sb = (long double)(xm - xl) * (yr - ym); long double sc = (long double)(xr - xm) * (ym - yl); LL mx, my; if(sa + sc > sb && sa + sb > sc) mx = (xl + xm) >> 1, my = (yl + ym) >> 1; else if(sb > sa + sc) mx = (xl + xm) >> 1, my = ym; else mx = xm, my = (yl + ym) >> 1; int d = query(mx, my); if(d == 1) solve(max(xl, mx + 1), xm, xr, yl, ym, yr); else if(d == 2) solve(xl, xm, xr, max(yl, my + 1), ym, yr); else solve(xl, min(mx, xm), xr, yl, min(my, ym), yr);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif LL n; scanf("%lld", &n); solve(1, n + 1, n + 1, 1, n + 1, n + 1); return 0;} D. Ants标准$2-sat$,利用线段树优化建图即可123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;vector<int> g[maxn], f[maxn << 2], g2[maxn * 50];int sz[maxn], fa[maxn], dep[maxn], son[maxn];int top[maxn], dfn[maxn];int fl[maxn << 2], fr[maxn << 2];int cnt = 0, tot;void dfs1(int u, int father) { dep[u] = dep[father] + 1; fa[u] = father; sz[u] = 1; son[u] = -1; for(auto v : g[u]) { if(v == father) continue; dfs1(v, u); sz[u] += sz[v]; if(son[u] == -1 || sz[v] > sz[son[u]]) son[u] = v; }}void dfs2(int u, int t) { top[u] = t; dfn[u] = ++cnt; if(son[u] == -1) return; dfs2(son[u], t); for(auto v : g[u]) { if(v == son[u] || v == fa[u]) continue; dfs2(v, v); }}void update(int t, int l, int r, int ll, int rr, int x) { if(ll <= l && r <= rr) { f[t].push_back(x); return; } int mid = (l + r) >> 1; if(ll <= mid) update(t << 1, l, mid, ll, rr, x); if(rr > mid) update(t << 1 | 1, mid + 1, r, ll, rr, x);}void fset(int u, int v, int k) { int x = top[u], y = top[v]; while(x != y) { int &w = dep[x] > dep[y] ? u : v; int &z = dep[x] > dep[y] ? x : y; update(1, 1, cnt, dfn[z], dfn[w], k); w = fa[z]; z = top[w]; } if(u == v) return; if(dfn[u] > dfn[v]) swap(u, v); update(1, 1, cnt, dfn[u] + 1, dfn[v], k);}int rev(int x) { if(x & 1) return x - 1; else return x + 1;}void add_edge(int x, int y) { g2[x].push_back(y); g2[rev(y)].push_back(rev(x));}void build(int t, int l, int r) { fl[t] = tot++; int pre = fl[t]; for(auto e : f[t]) { add_edge(pre << 1, rev(e)); add_edge(pre << 1, tot << 1); add_edge(e, tot << 1); pre = tot++; } fr[t] = pre; if(t > 1) add_edge(fr[t >> 1] << 1, fl[t] << 1); if(l == r) return; int mid = (l + r) >> 1; build(t << 1, l, mid); build(t << 1 | 1, mid + 1, r);}int pre[maxn * 50], low[maxn * 50], scc[maxn * 50];int dfs_t, scc_cnt;stack<int> ST;void dfs(int u) { pre[u] = low[u] = ++dfs_t; ST.push(u); for(auto v : g2[u]) { if(!pre[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(!scc[v]) { low[u] = min(low[u], pre[v]); } } if(low[u] == pre[u]) { scc_cnt++; while(!ST.empty()) { int x = ST.top(); ST.pop(); scc[x] = scc_cnt; if(x == u) break; } }}vector<int>g3[maxn * 50];int l[maxn * 50], q[maxn * 50], pc[maxn * 50];void Shrink_Point(int n) { for(int u = 0; u < n; u++) { for(auto v : g2[u]) { if(scc[u] != scc[v]) { g3[scc[v]].push_back(scc[u]); l[scc[u]]++; } } }}void dfsc(int u) { if(pc[u]) return; pc[u] = 2; for(auto v : g3[u]) dfsc(v);}bool find_scc(int n) { dfs_t = scc_cnt = 0; for(int i = 0; i < n; i++) { if(!pre[i]) dfs(i); } for(int i = 0; i < n; i += 2) { if(scc[i] == scc[i + 1]) return false; } Shrink_Point(n); int mm = 0; for(int i = 1; i <= scc_cnt; i++) { if(l[i] == 0) q[mm++] = i; } for(int i = 0; i < mm; i++) { for(auto v : g3[q[i]]) { l[v]--; if(l[v] == 0) q[mm++] = v; } } for(int i = 0; i < n; i += 2) { l[scc[i]] = scc[i + 1]; l[scc[i + 1]] = scc[i]; } for(int i = 0; i < mm; i++) { if(pc[q[i]]) continue; pc[q[i]] = 1; dfsc(l[q[i]]); } return true;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, i, u, v; scanf("%d", &n); for(i = 1; i < n; i++) { scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } dfs1(1, 0); dfs2(1, 1); scanf("%d", &m); for(i = 0; i < m; i++) { scanf("%d%d", &u, &v); fset(u, v, i << 1); scanf("%d%d", &u, &v); fset(u, v, i << 1 | 1); } tot = m; build(1, 1, cnt); if(!find_scc(tot * 2)) puts("NO"); else { puts("YES"); for(i = 0; i < m; i++) printf("%d\n", pc[scc[i << 1]]); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Avito Code Challenge 2018]]></title>
<url>%2F2018%2F05%2F30%2FCF-ACC%2F</url>
<content type="text"><![CDATA[F. Round Marriage题目传送门显然的霍尔定理利用前缀和处理一波最小区间即可 G. Magic multisets题目传送门拆分成区间+1和区间*2两种操作就是标准的双标记线段树了可以证明拆分后的操作数最多为2q(因为q中的每个区间最多被合并一次) H. K Paths题目传送门考虑树形dp$f[u]$表示存在从$u$开始的一部分是所有路径的公共部分的方案数然后就是简单的子树合并难点在于如果公共部分的端点刚好是$u$的时候如果另一个端点是$u$的祖先,分治$ntt$即可如果在$u$的子树内,考虑dp,逆操作还原回去即可逆操作复杂度小于$n\sqrt{n}$123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 998244353;const int maxn = 1e5 + 5;int add(int x, int y) { if((x += y) >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a, int b) { int r = 1; while(b) { if(b & 1) r = mul(r, a); a = mul(a, a); b >>= 1; } return r;}int wn[20];void GetWn() { for(int i = 0; i < 20; i++) { int t = 1 << i; wn[i] = powt(3, (mod - 1) / t); }}void NTT(int a[], int len, int t) { for (int i = 0, j = 0; i < len; i++) { if (i > j) swap(a[i], a[j]); for (int l = len >> 1; (j ^= l) < l; l >>= 1); } int id = 0; for(int h = 2; h <= len; h <<= 1) { id++; for(int j = 0; j < len; j += h) { int w = 1; for(int k = j; k < j + h / 2; ++k) { int u = a[k]; int t = mul(w, a[k + h / 2]); a[k] = add(u, t); a[k + h / 2] = add(u, mod - t); w = mul(w, wn[id]); } } } if(t == -1) { for(int i = 1; i < len / 2; i++) swap(a[i], a[len - i]); LL inv = powt(len, mod - 2); for(int i = 0; i < len; i++) a[i] = mul(a[i], inv); }}vector<int> g[maxn];unordered_map<int, int> q;int sz[maxn], f[maxn], n, k, ans;int p[maxn], inv[maxn];int a[maxn << 2], b[maxn << 2], c[maxn << 2], tot;void solve(int l, int r) { if(l == r) return; int mid = (l + r) >> 1, m, i; solve(l, mid); solve(mid + 1, r); for(m = 1; m <= r - l + 1; m <<= 1); a[0] = b[0] = 1; for(i = l; i <= mid; i++) a[i - l + 1] = c[i]; for(i -= l - 1; i < m; i++) a[i] = 0; for(i = mid + 1; i <= r; i++) b[i - mid] = c[i]; for(i -= mid; i < m; i++) b[i] = 0; NTT(a, m, 1); NTT(b, m, 1); for(i = 0;i < m; i++) a[i] = mul(a[i], b[i]); NTT(a, m, -1); for(i = 0;i <= r - l; i++) c[l + i] = a[i + 1];}void dfs(int u, int fa) { sz[u] = 1; for(auto v : g[u]) { if(v == fa) continue; dfs(v, u); sz[u] += sz[v]; ans = add(ans, mul(f[u], f[v])); f[u] = add(f[u], f[v]); } tot = 0; for(auto v : g[u]) { if(v == fa) c[tot++] = n - sz[u]; else c[tot++] = sz[v]; } q.clear(); solve(0, tot - 1); int d, res; for(auto v : g[u]) { if(v == fa) d = n - sz[u]; else d = sz[v]; if(q.find(d) == q.end()) { a[0] = res = 1; for(int i = 0;i < tot; i++) { a[i + 1] = add(c[i], mod - mul(a[i], d)); if(i < k) res = add(res, mul(a[i + 1], mul(p[k], inv[k - i - 1]))); } q[d] = res; } if(v == fa) f[u] = add(f[u], q[d]); else ans = add(ans, mul(f[v], q[d])); }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int i, u, v; GetWn(); scanf("%d%d", &n, &k); if(k == 1) return printf("%lld\n", 1LL * n * (n - 1) / 2 % mod), 0; if(n == 1) return puts("0"), 0; for(i = p[0] = 1; i < maxn; i++) p[i] = mul(p[i - 1], i); inv[maxn - 1] = powt(p[maxn - 1], mod - 2); for(i = maxn - 1; i > 0; i--) inv[i - 1] = mul(inv[i], i); for(i = 1; i < n; i++) { scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } dfs(1, 0); printf("%d\n", ans); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[NN country]]></title>
<url>%2F2018%2F05%2F17%2FCF-483-E%2F</url>
<content type="text"><![CDATA[题目传送门题意:给定一棵树,给$m$个公交车路线,即从$u$到$v$可直达不用换乘,给$q$次查询,问从$u -> v$最少需要多少次换乘 考虑分别求$u -> lca,v -> lca$,利用树上倍增维护$u$经过$2^{i}$次换乘最多向上走到哪里即可然后我们利用这个树上倍增可以求得换乘次数最少的能到达的点$u’, v’$,使得再经过一次换乘就能到达$lca$,记录下当前次数然后考虑,如果存在一条路线同时经过$u’, v’$那么答案就是$+1$,否则就是$+2$考虑离线询问,按$dfs$序访问$v’$时,将有一个端点在$v$且另一个端点$dfs$要小一些的路径加入树状数组开始访问$v’$的子树时区间查询$u’$的子树内的路径个数离开$v’$的子树时再区间查询$u’$的子树内的路径个数两者之差即是同时经过$u’, v’$的路径个数 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 2e5 + 5;vector<int> g[maxn];int depth = 0, bn = 0, b[maxn << 1];int f[maxn << 1], dfn[maxn], dr[maxn], ft[maxn];int fp[maxn][20], ans[maxn], cnt[maxn];vector<int> fq[maxn];vector<P> sq[maxn];void dfs(int u, int fa) { int tmp = ++depth; b[++bn] = tmp; f[tmp] = u; dfn[u] = bn; for (auto v : g[u]) { if (v == fa) continue; dfs(v, u); b[++bn] = tmp; } dr[u] = depth;}int st[maxn << 1][20];int lg[maxn << 1];void st_init() { for (int i = 2; i < maxn * 2; ++i) lg[i] = lg[i >> 1] + 1; for (int i = bn; i >= 1; --i) { st[i][0] = b[i]; for (int j = 1; i + (1 << j) - 1 <= bn; ++j) st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); }}int rmq(int l, int r) { int k = lg[r - l + 1]; return min(st[l][k], st[r - (1 << k) + 1][k]);}int lca(int a, int b) { if(a == b) return a; if (dfn[a] > dfn[b]) swap(a, b); int k = rmq(dfn[a], dfn[b]); return f[k];}void update(int &x, int y) { if(y && (!x || dfn[x] > dfn[y])) x = y;}void dfs2(int u, int fa) { for (auto v : g[u]) { if (v == fa) continue; dfs2(v, u); if(fp[v][0] != u) update(fp[u][0], fp[v][0]); }}void dfs3(int u, int fa) { for(int i = 1; i < 20; i++) fp[u][i] = fp[fp[u][i - 1]][i - 1]; for (auto v : g[u]) { if (v == fa) continue; dfs3(v, u); }}void add(int x) { while(x < maxn) { ft[x]++; x += x & (-x); }}int query(int x) { int res = 0; while(x > 0) { res += ft[x]; x -= x & (-x); } return res;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, u, v, i, j, k; scanf("%d", &n); for(i = 2; i <= n; i++) { scanf("%d", &u); g[u].push_back(i); } dfs(1, 0); st_init(); scanf("%d", &m); for(i = 1; i <= m; i++) { scanf("%d%d", &u, &v); k = lca(u, v); if(k != u) update(fp[u][0], k); if(k != v) update(fp[v][0], k); if(dfn[u] > dfn[v]) swap(u, v); fq[b[dfn[v]]].push_back(b[dfn[u]]); } dfs2(1, 0); dfs3(1, 0); scanf("%d", &m); for(i = 1; i <= m; i++) { scanf("%d%d", &u, &v); k = lca(u, v); if(dfn[u] > dfn[v]) swap(u, v); for(j = 19; j >= 0; j--) { if(dfn[fp[u][j]] > dfn[k]) { ans[i] += 1 << j; u = fp[u][j]; } if(dfn[fp[v][j]] > dfn[k]) { ans[i] += 1 << j; v = fp[v][j]; } } if(u == k) { if(!fp[v][0]) ans[i] = -1; else ans[i]++; } else { if(!fp[u][0] || !fp[v][0]) ans[i] = -1; else { ans[i] += 2; sq[b[dfn[v]] - 1].push_back(P(u, -i)); sq[dr[v]].push_back(P(u, i)); } } } for(i = 0; i <= n; i++) { for(auto e : fq[i]) add(e); for(auto e : sq[i]) { k = query(dr[e.fi]) - query(b[dfn[e.fi]] - 1); if(e.se < 0) cnt[-e.se] -= k; else cnt[e.se] += k; } } for(i = 1; i <= m; i++) { if(cnt[i]) ans[i]--; printf("%d\n", ans[i]); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[May Holidays]]></title>
<url>%2F2018%2F05%2F05%2FCF-477-E%2F</url>
<content type="text"><![CDATA[题目传送门树链剖分+分块123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1e5 + 5;const int mod = 1e9 + 7;vector<int> g[maxn];int sz[maxn], fa[maxn], dep[maxn], son[maxn];int top[maxn], dfn[maxn];int cnt = 0;void dfs1(int u, int father) { dep[u] = dep[father] + 1; fa[u] = father; sz[u] = 1; son[u] = -1; for(auto v : g[u]) { if(v == father) continue; dfs1(v, u); sz[u] += sz[v]; if(son[u] == -1 || sz[v] > sz[son[u]]) son[u] = v; }}void dfs2(int u, int t) { top[u] = t; dfn[u] = ++cnt; if(son[u] == -1) return; dfs2(son[u], t); for(auto v : g[u]) { if(v == son[u] || v == fa[u]) continue; dfs2(v, v); }}int a[maxn], fd[maxn];int fl[405], fr[405], tag[405], ans = 0;bool off[maxn];unsigned char fp[405][maxn << 1];void add(int k, int l, int r, int v) { for(int i = l;i <= r; i++) { if(off[i]) { a[i] += v; continue; } if(a[i] + tag[k] < maxn) ans--; fp[k][a[i]]--; a[i] += v; if(a[i] + tag[k] < maxn) ans++; fp[k][a[i]]++; }}void add(int x, int v) { off[x] ^= 1; ans += v * (a[x] + tag[fd[x]] < maxn); fp[fd[x]][a[x]] += v;}void update(int l, int r, int v) { if(fd[l] == fd[r]) add(fd[l], l, r, v); else { add(fd[l], l, fr[fd[l]], v); add(fd[r], fl[fd[r]], r, v); for(int i = fd[l] + 1;i < fd[r]; i++) { if(v < 0) ans += fp[i][maxn - tag[i]]; tag[i] += v; if(v > 0) ans -= fp[i][maxn - tag[i]]; } }}void modify(int u, int v, int val) { int x = top[u], y = top[v]; while(x != y) { int &w = dep[x] > dep[y] ? u : v; int &z = dep[x] > dep[y] ? x : y; update(dfn[z], dfn[w], val); w = fa[z]; z = top[w]; } u = dfn[u]; v = dfn[v]; if(u > v) swap(u, v); update(u, v, val);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, i, j, u; scanf("%d%d", &n, &m); for(i = 2; i <= n; i++) { scanf("%d", &u); g[u].push_back(i); } dfs1(1, 0); dfs2(1, 1); for(i = 1; i <= n; i++) scanf("%d", &a[dfn[i]]); for(i = 1; i <= n; i++) a[i] += maxn; fl[1] = 1; for(i = j = u = 1; i <= n; i++, u++) { if(u == 333) { j++; u = 1; fl[j] = i; } fd[i] = j; fr[j] = i; fp[j][a[i]]++; } for(i = 0;i < m; i++) { scanf("%d", &u); if(u > 0) { add(dfn[u], -1); modify(u, 1, -1); } else { add(dfn[-u], 1); modify(-u, 1, 1); } printf("%d%c", ans, " \n"[i + 1 == m]); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Perpetual Subtraction]]></title>
<url>%2F2018%2F04%2F29%2FCF_470_E%2F</url>
<content type="text"><![CDATA[题目传送门可以很容易的得出dp方程然后得出转移矩阵矩阵快速幂优化dp即可由于这个矩阵很大,我们需要考虑更多优化因为转移矩阵是个上三角矩阵,所以可以进行对角化对角化之后发现特征向量矩阵乘一个向量其实就是一个卷积,可以用$fft$优化然后就神奇的在$nlogn$时间复杂度内做出来了123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;const int N = 1 << 18;const int P = 998244353;const int G = 3;const int NUM = 20;int wn[NUM];int mul(int x, int y) { LL z = 1LL * x * y; return z - z / P * P;}int add(int x, int y) { x += y; if(x >= P) x -= P; return x;}int powt(int a, LL b) { int ans = 1; while(b) { if(b & 1) ans = mul(ans, a); b >>= 1; a = mul(a, a); } return ans;}void GetWn() { for(int i = 0; i < NUM; i++) { int t = 1 << i; wn[i] = powt(G, (P - 1) / t); }}void NTT(int a[], int len, int t) { for (int i = 0, j = 0; i < len; i++) { if (i > j) swap(a[i], a[j]); for (int l = len >> 1; (j ^= l) < l; l >>= 1); } int id = 0; for(int h = 2; h <= len; h <<= 1) { id++; for(int j = 0; j < len; j += h) { int w = 1; for(int k = j; k < j + h / 2; ++k) { int u = a[k]; int t = mul(w, a[k + h / 2]); a[k] = add(u, t); a[k + h / 2] = add(u, P - t); w = mul(w, wn[id]); } } } if(t == -1) { for(int i = 1; i < len / 2; i++) swap(a[i], a[len - i]); LL inv = powt(len, P - 2); for(int i = 0; i < len; i++) a[i] = mul(a[i], inv); }}int a[maxn], p[maxn], inv[maxn];int f[N], g[N];int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif GetWn(); int n, i; LL m; scanf("%d%lld", &n, &m); for(i = 0;i <= n; i++) scanf("%d", &a[i]); for(i = p[0] = 1;i <= n; i++) p[i] = mul(p[i - 1], i); inv[n] = powt(p[n], P - 2); for(i = n - 1;i >= 0; i--) inv[i] = mul(inv[i + 1], i + 1); for(i = 0;i <= n; i++) f[i] = inv[i]; for(i = 0;i <= n; i++) g[n - i] = mul(p[i], a[i]); NTT(f, N, 1); NTT(g, N, 1); for(i = 0;i < N; i++) f[i] = mul(f[i], g[i]); NTT(f, N, -1); for(i = 0;i <= n; i++) a[i] = mul(mul(f[n - i], inv[i]), powt(powt(i + 1, P - 2), m)); memset(f, 0, sizeof(f)); memset(g, 0, sizeof(g)); for(i = 0;i <= n; i++) f[i] = inv[i]; for(i = 0;i <= n; i++) { g[n - i] = mul(p[i], a[i]); if(i & 1) g[n - i] = add(0, P - g[n - i]); } NTT(f, N, 1); NTT(g, N, 1); for(i = 0;i < N; i++) f[i] = mul(f[i], g[i]); NTT(f, N, -1); for(i = 0;i <= n; i++) { a[i] = mul(f[n - i], inv[i]); if(i & 1) a[i] = add(0, P - a[i]); } for(i = 0;i <= n; i++) printf("%d ", a[i]); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Circles of Waiting]]></title>
<url>%2F2018%2F04%2F29%2FCF_475_E%2F</url>
<content type="text"><![CDATA[题目传送门很容易列出期望的方程,高斯消元搞一波但是常规消元复杂度是$O(r^6)$的考虑从左到右从上到下编号然后按编号从小到大消元假设黄点是已经消元的点,那么消下一个点的时候,只有绿点的方程中该项系数不为0同时,该点的方程中也只有绿点的那些项的系数不为0由于绿点的个数是$O(r)$的,那么每次消元的复杂度就是$O(r^2)$的总体消元复杂度就是$O(r^4)$的然后现在得到了上三角矩阵由于只需要求$(0,0)$点的值所以只需要把那一行的其它元消掉这个的复杂度也是$O(r^4)$的总体复杂度是$O(r^4)$123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 8005;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a, int b) { int r = 1; while(b) { if(b & 1) r = mul(r, a); a = mul(a, a); b >>= 1; } return r;}int f[maxn][maxn];int id[111][111], a[4], dx[4] = { -1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};vector<int> c;int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n = 0, r, i, j, k, x, y, u, v; scanf("%d", &r); for(i = j = 0; i < 4; i++) { scanf("%d", &a[i]); j += a[i]; } j = powt(j, mod - 2); for(i = 0; i < 4; i++) a[i] = mod - mul(a[i], j); for(i = -r; i <= r; i++) { for(j = -r; j <= r; j++) { if(i * i + j * j <= r * r) id[i + 55][j + 55] = ++n; } } for(i = -r; i <= r; i++) { for(j = -r; j <= r; j++) { if(u = id[i + 55][j + 55]) { f[u][0] = f[u][u] = 1; for(k = 0; k < 4; k++) { x = i + dx[k]; y = j + dy[k]; if(v = id[x + 55][y + 55]) f[u][v] = a[k]; } } } } for(i = 1;i <= n; i++) { u = min(n, i + r * 2 + 1); c.clear(); c.push_back(0); for(j = i;j <= u; j++) { if(f[i][j]) c.push_back(j); } for(j = i + 1;j <= u; j++) { if(f[j][i]) { v = mul(mod - f[j][i], powt(f[i][i], mod - 2)); for(auto e:c) f[j][e] = add(f[j][e], mul(f[i][e], v)); } } } u = id[55][55]; for(i = 1;i <= n; i++) { if(i == u) continue; if(f[u][i]) { v = mul(mod - f[u][i], powt(f[i][i], mod - 2)); for(j = 0;j <= n; j++) f[u][j] = add(f[u][j], mul(f[i][j], v)); } } v = powt(f[u][u], mod - 2); printf("%d\n", mul(f[u][0], v)); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Visible Black Areas]]></title>
<url>%2F2018%2F04%2F23%2FCF_edu42_G%2F</url>
<content type="text"><![CDATA[题目传送门求出边与方框的交点,并记录边的朝向,得到出点和入点方框内的图形在方框上的点一定是入点出点交错先并查集合并相邻出点-入点,再合并入点-出点 即可注意边界情况和各种特殊情况 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;struct Point { int x, y; Point(int _x = 0, int _y = 0): x(_x), y(_y) {} Point operator + (const Point &b) const { return Point(x + b.x, y + b.y); } Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); } int operator ^ (const Point &b) const { return (x * b.y - y * b.x); }} p[maxn];Point a, b, c, d, e;int w, h;vector<P> f;bool isPointOnSegment(Point p, Point s, Point e) { return ((p - s) ^ (s - e)) == 0 && ((p.x - s.x) * (p.x - e.x)) <= 0 && ((p.y - s.y) * (p.y - e.y)) <= 0;}void pre_solve(Point u, Point v) { if(u.x == v.x) { if(u.x == a.x || u.x == b.x) return; if(min(u.y, v.y) >= c.y || max(u.y, v.y) <= a.y) return; if(abs(u.y - a.y) < abs(u.y - d.y)) { e = Point(u.x, a.y); if(isPointOnSegment(e, a, b) && isPointOnSegment(e, u, v)) f.push_back(P(e.x - a.x, ((b - a) ^ (v - a)) > 0)); e = Point(u.x, c.y); if(isPointOnSegment(e, c, d) && isPointOnSegment(e, u, v)) f.push_back(P(w + h + c.x - e.x, ((d - c) ^ (v - c)) > 0)); } else { e = Point(u.x, c.y); if(isPointOnSegment(e, c, d) && isPointOnSegment(e, u, v)) f.push_back(P(w + h + c.x - e.x, ((d - c) ^ (v - c)) > 0)); e = Point(u.x, a.y); if(isPointOnSegment(e, a, b) && isPointOnSegment(e, u, v)) f.push_back(P(e.x - a.x, ((b - a) ^ (v - a)) > 0)); } } else { if(u.y == a.y || u.y == d.y) return; if(min(u.x, v.x) >= c.x || max(u.x, v.x) <= a.x) return; if(abs(u.x - a.x) < abs(u.x - b.x)) { e = Point(a.x, u.y); if(isPointOnSegment(e, a, d) && isPointOnSegment(e, u, v)) f.push_back(P(w + w + h + d.y - e.y, ((a - d) ^ (v - d)) > 0)); e = Point(c.x, u.y); if(isPointOnSegment(e, b, c) && isPointOnSegment(e, u, v)) f.push_back(P(w + e.y - b.y, ((c - b) ^ (v - b)) > 0)); } else { e = Point(c.x, u.y); if(isPointOnSegment(e, b, c) && isPointOnSegment(e, u, v)) f.push_back(P(w + e.y - b.y, ((c - b) ^ (v - b)) > 0)); e = Point(a.x, u.y); if(isPointOnSegment(e, a, d) && isPointOnSegment(e, u, v)) f.push_back(P(w + w + h + d.y - e.y, ((a - d) ^ (v - d)) > 0)); } }}int inConvexPoly(int n, Point a) { p[n] = p[0]; for(int i = 0; i < n; i++) { if(((p[i] - a) ^ (p[i + 1] - a)) < 0) return 0; else if(isPointOnSegment(a, p[i], p[i + 1])) return 1; } return 1;}int check(int n) { int vis = 1; for(int i = 0; i < n; i++) { if(a.x <= p[i].x && p[i].x <= c.x && a.y <= p[i].y && p[i].y <= c.y) vis &= 1; else vis = 0; } if(!vis) { vis = 1; vis &= inConvexPoly(n, a); vis &= inConvexPoly(n, b); vis &= inConvexPoly(n, c); vis &= inConvexPoly(n, d); } return vis;}int fp[maxn], tot;int ff(int x) { if(fp[x] != x) fp[x] = ff(fp[x]); return fp[x];}void funion(int x, int y) { x = ff(x); y = ff(y); if(x != y) { fp[x] = y; tot--; }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, i; scanf("%d%d%d%d", &a.x, &c.y, &c.x, &a.y); b = Point(c.x, a. y); d = Point(a.x, c. y); w = c.x - a.x; h = c.y - a.y; scanf("%d", &n); for(i = 0; i < n; i++) scanf("%d%d", &p[i].x, &p[i].y); p[n] = p[0]; for(i = 0; i < n; i++) pre_solve(p[i], p[i + 1]); tot = m = f.size(); if(m == 0) { printf("%d\n", check(n)); return 0; } for(i = 0; i <= (w + h) * 2; i++) fp[i] = i; for(i = 1; i < m; i++) { if(f[i - 1].se == 1 && f[i].se == 0) funion(f[i - 1].fi, f[i].fi); } if(f[m - 1].se == 1 && f[0].se == 0) funion(f[m - 1].fi, f[0].fi); sort(f.begin(), f.end()); f.push_back(f[0]); for(i = 0; i < m; i++) { if(f[i].se == 0 && f[i + 1].se == 1) funion(f[i].fi, f[i + 1].fi); } printf("%d\n", tot); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[2018川大校赛补]]></title>
<url>%2F2018%2F04%2F23%2F2018scu%2F</url>
<content type="text"><![CDATA[SCU-4581由于内存限制,对$v < 1e6$做普通背包,对$n < 20$做容斥即可想到了容斥居然想不出组合数公式123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int BUFFER_MAX_SIZE = 100000;struct Quick_In { char buf[BUFFER_MAX_SIZE], *ps = buf, *pe = buf + 1; inline void InNext() { if (++ps == pe) pe = (ps = buf) + fread(buf, sizeof(char), sizeof(buf) / sizeof(char), stdin); } template<class T> inline bool operator()(T &number) { number = 0; T f = 1; bool vis_point = 0; if (ps == pe) return false; //EOF do { InNext(); if ('-' == *ps) f = -1; } while (ps != pe && !isdigit(*ps)); if (ps == pe) return false; //EOF do { if((*ps) == '.') vis_point = 1; else { number = number * 10 + *ps - 48; if(vis_point) f *= 0.1; } InNext(); } while (ps != pe && (isdigit(*ps) || (*ps) == '.')); number *= f; return true; }} In;const int maxn = 2e5 + 5;const int mod = 1e9 + 7;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int x, int y) { int r = 1; while(y) { if(y & 1) r = mul(r, x); x = mul(x, x); y >>= 1; } return r;}int f[maxn], a[20];int C(int n, int m) { if(m > n) return 0; int res = 1; for(int i = 0;i < m; i++) res = mul(res, mul(n - i, powt(i + 1, mod - 2))); return res;}void solve() { int n, v, w, c, i, j, res; In(n); In(v); if(v < maxn) { for(i = 0; i <= v; i++) f[v] = 0; f[0] = 1; for(i = 0; i < n; i++) { In(c); for(j = v - c + 1, res = 0; j <= v; j++) res = add(res, f[j]); for(j = v; j > 0; j--) { res = add(res, mod - f[j]); if(j >= c) res = add(res, f[j - c]); f[j] = add(f[j], res); } } printf("%d\n", f[v]); } else { for(i = 0;i < n; i++) In(a[i]); for(i = res = 0;i < (1 << n); i++) { for(j = c = 0, w = v;j < n; j++) { if((i >> j) & 1) { w -= a[j] + 1; c++; } } if(c & 1) res = add(res, mod - C(w + n - 1, n - 1)); else res = add(res, C(w + n - 1, n - 1)); } printf("%d\n", res); }}int main() {#ifdef CX_TEST //freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; scanf("%d", &t); while(t--) solve(); return 0;} SCU-4589题意:求质数的$k$次方前缀和一种类似欧拉筛法的基本应用吧复杂度是$O(k * n^{3/4}/logn)$的这个手写$k$次方自然数前缀和真恶心123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1e5 + 5;int mod, k;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}LL mul(LL a, LL b, LL m) { LL r = (a * b - (LL)(((long double)a * b) / m) * m); r = r - r / m * m; if(r < 0) r += m; return r;}int powt(int x, int y) { int r = 1; while(y) { if(y & 1) r = mul(r, x); x = mul(x, x); y >>= 1; } return r;}int fg[maxn], pri[maxn];LL sum[maxn];int cnt = 0;void GetPrime() { for (int i = 2; i < maxn; ++i) { if (!fg[i]) pri[cnt++] = i; for (int j = 0; j < cnt && pri[j] * i < maxn; ++j) { fg[pri[j] * i] = 1; if (i % pri[j] == 0) break; } }}int S(int n) { int res; if(k == 0) res = n % mod; else if(k == 1) res = 1LL * n * (n + 1) / 2 % mod; else if(k == 2) { LL m = 1LL * mod * 6; res = mul(mul(n, n + 1, m), 2 * n + 1, m) / 6; } else if(k == 3) { LL m = 1LL * mod * 4; res = mul(mul(n, n + 1, m), mul(n, n + 1, m), m) / 4; } else if(k == 4) { LL m = 1LL * mod * 30; LL d = mul(6LL * n + 9, n, m); d = mul(d + 1, n, m) + m - 1; res = mul(d, mul(n, n + 1, m), m) / 30; } else if(k == 5) { LL m = 1LL * mod * 12; LL d = mul(2LL * n + 4, n, m); d = mul(d + 1, n, m) + m - 1; res = mul(d, mul(mul(n, n, m), n + 1, m), m) / 12; } else if(k == 6) { LL m = 1LL * mod * 42; LL d = mul(6LL * n + 15, n, m); d = mul(d + 6, n, m); d = mul(d + m - 6, n, m); d = mul(d + m - 1, n, m) + 1; res = mul(d, mul(n, n + 1, m), m) / 42; } else if(k == 7) { LL m = 1LL * mod * 24; LL d = mul(3LL * n + 9, n, m); d = mul(d + 5, n, m); d = mul(d + m - 5, n, m); d = mul(d + m - 2, n, m) + 2; res = mul(d, mul(mul(n, n, m), n + 1, m), m) / 24; } else if(k == 8) { LL m = 1LL * mod * 90; LL d = mul(10LL * n + 35, n, m); d = mul(d + 25, n, m); d = mul(d + m - 25, n, m); d = mul(d + m - 17, n, m); d = mul(d + 17, n, m); d = mul(d + 3, n, m) + m - 3; res = mul(d, mul(n, n + 1, m), m) / 90; } else if(k == 9) { LL m = 1LL * mod * 20; LL d = mul(2LL * n + 8, n, m); d = mul(d + 7, n, m); d = mul(d + m - 7, n, m); d = mul(d + m - 7, n, m); d = mul(d + 7, n, m); d = mul(d + 3, n, m) + m - 3; res = mul(d, mul(mul(n, n, m), n + 1, m), m) / 20; } else { LL m = 1LL * mod * 66; LL d = mul(6LL * n + 27, n, m); d = mul(d + 28, n, m); d = mul(d + m - 28, n, m); d = mul(d + m - 38, n, m); d = mul(d + 38, n, m); d = mul(d + 28, n, m); d = mul(d + m - 28, n, m); d = mul(d + m - 5, n, m) + 5; res = mul(d, mul(n, n + 1, m), m) / 66; } return add(res, mod - 1);}LL fa[maxn], fb[maxn];void solve() { LL i, r, n; scanf("%lld%d%d", &n, &k, &mod); for(r = 1; 1LL * r * r <= n; r++) fa[r] = S(r); for(i = 1; i < r; i++) fb[i] = S(n / i); for(LL p = 2; p < r; p++) { if(!fg[p]) { int pw = powt(p, k); for(i = 1; i <= min(r - 1, n / p / p); i++) { if(p * i < r) fb[i] = add(fb[i], mod - mul(pw, add(fb[i * p], mod - fa[p - 1]))); else fb[i] = add(fb[i], mod - mul(pw, add(fa[n / p / i], mod - fa[p - 1]))); } for(i = r - 1; i >= p * p; i--) fa[i] = add(fa[i], mod - mul(pw, add(fa[i / p], mod - fa[p - 1]))); } } printf("%lld\n", fb[1]);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; GetPrime(); scanf("%d", &t); while(t--) solve(); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CDOJ 1825 柱爷搞搞搞搞搞xxxxoooorrrrr]]></title>
<url>%2F2018%2F02%2F27%2FCDOJ%201825%2F</url>
<content type="text"><![CDATA[题面传送门类似数位DP的思想,考虑对于这$n$个数的前$i$位,我们对每个数的前$i$位选的都是它的上界(最大值),那么这前$i$位的异或和结果只有一种,然后我们考虑它们的第$i + 1$位存在一些数选的不是上界,假设第一个没有选上界的数为第$j$个,那么存在其它数随便选后,第$j$个数最后总能选择一个数使得最后的异或和为给定值.(因为第$j$个数能选择的数的范围是一个全集)我们可以$O(n)$的DP出前$i$位都选上界,第$i + 1$位存在一些数选的不是上界的情况下产生的方案数.按位枚举,总复杂度就是$nlog_{2}1e9$整体思想类似DP套DP 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1e5 + 5;const int mod = 1e9 + 7;void add(int &x, int y) { x += y; if(x >= mod) x -= mod;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int f[maxn][2][2], a[maxn];int solve(int n, int k, int e) { int i, j, res = (1 << k) - 1; memset(f, 0, sizeof(f)); f[0][0][0] = 1; for(i = 0; i < n; i++) { j = (a[i] & res) + 1; if((a[i] >> k) & 1) { add(f[i + 1][0][1], f[i][0][0]); add(f[i + 1][1][1], f[i][1][0]); add(f[i + 1][0][1], mul(f[i][0][1], 1 << k)); add(f[i + 1][1][1], mul(f[i][1][1], 1 << k)); add(f[i + 1][1][0], mul(f[i][0][0], j)); add(f[i + 1][0][0], mul(f[i][1][0], j)); add(f[i + 1][1][1], mul(f[i][0][1], j)); add(f[i + 1][0][1], mul(f[i][1][1], j)); } else { f[i + 1][0][0] = mul(f[i][0][0], j); f[i + 1][0][1] = mul(f[i][0][1], j); f[i + 1][1][0] = mul(f[i][1][0], j); f[i + 1][1][1] = mul(f[i][1][1], j); } } return f[n][e][1];}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, i, k, sum = 0, ans = 0; scanf("%d%d", &n, &k); for(i = 0; i < n; i++) { scanf("%d", &a[i]); sum ^= a[i]; } for(i = 30; i >= 0; i--) { add(ans, solve(n, i, (k >> i) & 1)); if((sum >> i) != (k >> i)) break; } if(sum == k) add(ans, 1); printf("%d\n", ans); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[hdu5848 Easy Homework]]></title>
<url>%2F2018%2F01%2F23%2Fhdu5848%2F</url>
<content type="text"><![CDATA[题面传送门感觉非常恶心的数学题…………首先我们需要先发现这个等式$f_{n}^{2}-f_{n-1}f_{n+1}=(-1)^{n}$证明的话把通项公式代入,再联系该数列的特征方程并利用韦达定理就行了对$n$分奇偶性讨论,然后令$f_{n} = x,f_{n - 1} = y$的话就是一个关于$y$的一元二次方程了利用二次剩余解出$y$,没有二次剩余就无解有了$x,y$就相当于有了终状态$B$构造转移矩阵$A$求$A^{k}=B\%p$的解,可以用BSGS实现另一个难点可能是BSGS的范围……我们知道这个数列在模$p$意义下是有循环节的,对于这道题,循环节规模在$O(p)$量级,可以利用通用的矩阵的循环节公式求得最小循环节……这个循环节大小就是BSGS的范围有点卡常数……需要手写hash表才行……或许是我写得太挫了update:那个转移矩阵可以只用两个元素表示……似乎可减少一半的常数?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1e5 + 5;int mod, wf;default_random_engine generator(time(NULL));uniform_int_distribution<LL> df(1, 1e18);int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a, int b) { int r = 1; while(b) { if(b & 1) r = mul(r, a); a = mul(a, a); b >>= 1; } return r;}template<typename T, typename U>struct HashMap { static const int M = 333331; int chk[M], cn; int q[M], qn; vector<T> a; vector<U> b; int fst[M], m; vector<int> nxt; HashMap() { memset(fst, -1, sizeof fst); cn++; } void clear() { for (int i = 0; i < qn; i++) fst[q[i]] = -1; cn++; qn = m = 0; a.clear(), b.clear(), nxt.clear(); } U& operator[](T x) { int r = (x % M + M) % M; for (int e = fst[r]; ~e; e = nxt[e]) { if (a[e] == x) { return b[e]; } } if (chk[r] != cn) { chk[r] = cn; q[qn++] = r; } a.push_back(x), b.push_back(U()); nxt.push_back(fst[r]), fst[r] = m++; return b.back(); } bool count(T x) { int r = (x % M + M) % M; for (int e = fst[r]; ~e; e = nxt[e]) { if (a[e] == x) { return 1; } } return 0; }};const int msize = 2;struct matrix { int a[msize][msize]; void clear() { memset(a, 0, sizeof(a)); } matrix operator *(const matrix &b) const { matrix tmp; tmp.clear(); for(int i = 0; i < msize; i++) { for(int j = 0; j < msize; j++) { for(int k = 0; k < msize; k++) { tmp.a[i][j] = add(tmp.a[i][j], mul(a[i][k], b.a[k][j])); } } } return tmp; } bool operator ==(const matrix &b) const { for(int i = 0; i < msize; i++) { for(int j = 0; j < msize; j++) { if(a[i][j] != b.a[i][j]) return false; } } return true; }};matrix powt(matrix a, LL b) { matrix r = {1, 0, 0, 1}; while(b) { if(b & 1) r = r * a; a = a * a; b >>= 1; } return r;}struct node { int p, d; node operator * (const node &b) const { node r; r.p = add(mul(p, b.p), mul(mul(d, b.d), wf)); r.d = add(mul(p, b.d), mul(d, b.p)); return r; }};node powt(node a, int b) { node r = node{1, 0}; while(b) { if(b & 1) r = r * a; a = a * a; b >>= 1; } return r;}int Legendre(int a) { return powt(a, (mod - 1) >> 1);}int get_ans(int x) { if(x == 0) return 0; if(powt(x, (mod - 1) >> 1) + 1 == mod) return -1; int a; while(true) { a = df(generator) % mod; wf = add(mul(a, a), mod - x); if(Legendre(wf) + 1 == mod) break; } node tmp = node{a, 1}; return powt(tmp, (mod + 1) >> 1).p;}int pri[maxn], cnt = 0;void GetPrime() { for (int i = 2; i < maxn; ++i) { if (!pri[i]) pri[cnt++] = i; for (int j = 0; j < cnt && pri[j] * i < maxn; ++j) { pri[pri[j] * i] = 1; if (i % pri[j] == 0) break; } }}vector<int> fac;void get_fac(int x) { for(int i = 0; pri[i] * pri[i] <= x; i++) { while(x % pri[i] == 0) { fac.push_back(pri[i]); x /= pri[i]; } } if(x > 1) fac.push_back(x);}LL get_cycle(int a) { matrix r = {a, 1, 1, 0}; matrix u = {1, 0, 0, 1}; fac.clear(); get_fac(mod - 1); //get_fac(mod - 1); get_fac(mod + 1); fac.push_back(mod); int n = fac.size(); LL d = 1; for(int i = 0; i < n; i++) { matrix v = r; for(int j = i + 1; j < n; j++) v = powt(v, fac[j]); if(u == v) continue; d *= fac[i]; r = powt(r, fac[i]); } return d;}HashMap <LL, int> q;LL solve(int fa, int a, int b, LL len, LL l, LL r, int k) { int i, j, m = ceil(sqrt(1.0 * len)); LL x, dl, dr, ans = 0; matrix v = {fa, 1, 1, 0}; matrix u = {add(mul(fa, b), a), b, b, a}; q.clear(); for(i = 0; i < m; i++) { q[1LL * u.a[0][0] * mod + u.a[1][0]] = i; u = u * v; } u = v = powt(v, m); for(i = 1; i <= m; i++) { if(q.count(1LL * u.a[0][0] * mod + u.a[1][0])) { j = q[1LL * u.a[0][0] * mod + u.a[1][0]]; x = 1LL * i * m - j; if(x <= len) { dl = (l - 1) / len; dr = r / len; if((l - 1) % len >= x) dl++; if(r % len >= x) dr++; if(len & 1) { if(((x + dl * len) & 1) == k) ans += (dr - dl + 1) / 2; else ans += (dr - dl) / 2; } else { if((x & 1) == k) ans += dr - dl; } } break; } u = u * v; } return ans;}void solve() { int a, x, u, d, y1, y2, inv; LL l, r, ans = 0; scanf("%d%d%d%lld%lld", &a, &mod, &x, &l, &r); LL len = get_cycle(a); inv = (mod + 1) >> 1; d = mul(a, x); d = add(mul(d, d), mul(4, mul(x, x))); u = get_ans(add(d, mul(4, mod - 1))); if(u > 0) { y1 = mul(add(u, mod - mul(a, x)), inv); y2 = mul(mod - add(u, mul(a, x)), inv); ans += solve(a, y1, x, len, l, r, 1); ans += solve(a, y2, x, len, l, r, 1); } u = get_ans(add(d, 4)); if(u > 0) { y1 = mul(add(u, mod - mul(a, x)), inv); y2 = mul(mod - add(u, mul(a, x)), inv); ans += solve(a, y1, x, len, l, r, 0); ans += solve(a, y2, x, len, l, r, 0); } printf("%lld\n", ans);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; GetPrime(); scanf("%d", &t); while(t--) solve(); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Power Substring]]></title>
<url>%2F2018%2F01%2F17%2FCF_Hello2018_G%2F</url>
<content type="text"><![CDATA[题目传送门考虑求$a * 10 ^ {m} + x \equiv 2 ^ {k} \% 10 ^ {n + m}$,$n$是$a$在十进制下的位数然后考虑中国剩余定理,先求一个满足$a*10^{m}+x \equiv 2^{k} \% 2^{n+m}$的解令$k > n + m,y = (a*10^{m}+x) \% 2^{n + m} + i * 2^{n + m}$,因为对于$2^{k} \% 5^{n+m}$来说,$2$是模数的一个原根,只要保证$y \% 5 != 0$就可以保证存在$k$满足所有等式然后转为求$(y / 2^{n + m}) \equiv 2 ^{k} \% 5 ^ {n + m}$的$k$的值然后有个公式可以优化:若$a ^ {k} \equiv c \% p^{i}$则存在$0 \leq j \leq p - 1$满足$a ^ {k + j * \varphi(p^{i})} \equiv c \% p^{i+1}$123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1e5 + 5;LL mod;LL add(LL x, LL y) { x += y; if(x >= mod) x -= mod; return x;}LL mul(LL a, LL b) { LL r = (a * b - (LL)(((long double)a * b) / mod) * mod); return add(r - r / mod * mod, mod);}LL powt(LL a,LL b) { LL r = 1; while(b >= 1) { if(b & 1) r = mul(r,a); a = mul(a,a); b >>= 1; } return r;}int f[] = { -1, 0, 1, 3, 2};int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t, n, m, i; LL a, b, x, k, phi; scanf("%d", &t); while(t--) { scanf("%lld", &a); n = to_string(a).size(); for(m = 0, b = 1; 1; m++, a *= 10, b *= 10) { x = a; mod = 1LL << (n + m); if(x % mod) x += mod - x % mod; if(x % 5 == 0) x += mod; if(x % mod == 0 && x % 5 && x - a < b) { x >>= n + m; k = f[x % 5]; for(i = 1,phi = 4,mod = 25; i < n + m; i++,mod *= 5,phi *= 5) { while(powt(2,k) != x % mod) k += phi; } printf("%lld\n",n + m + k); break; } } } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_GoodBye2017简单题解]]></title>
<url>%2F2018%2F01%2F17%2FCF_goodbye2017%2F</url>
<content type="text"><![CDATA[题目传送门 A.New Year and Counting Cards签到题12345678910111213141516171819char s[maxn];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif scanf("%s",s); int n = strlen(s); int t = 0; for(int i = 0;i < n; i++) { if(s[i] >= 'a' && s[i] <= 'z') { if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u') t++; } else { if(s[i] == '1' || s[i] == '3' || s[i] == '5' || s[i] == '7' || s[i] == '9') t++; } } printf("%d\n",t); return 0;} B.New Year and Buggy Bot签到题……手残打错一个小于号1234567891011121314151617181920212223242526272829303132333435363738394041char p[55][55];char s[maxn];int n,m,f[4],d[maxn];bool check(int w) { int i,j,k; for(i = 0;i < n; i++) { for(j = 0;j < m; j++) { if(p[i][j] == 'S') break; } if(j < m) break; } for(k = 0;k < w; k++) { if(d[k] == 0) i++; else if(d[k] == 1) i--; else if(d[k] == 2) j++; else j--; if(i < 0 || i == n || j < 0 || j == m) return false; if(p[i][j] == '#') return false; if(p[i][j] == 'E') return true; } return false;}int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int w,i,ans = 0; scanf("%d%d",&n,&m); for(i = 0;i < n; i++) scanf("%s",p[i]); scanf("%s",s); w = strlen(s); for(i = 0;i < 4; i++) f[i] = i; do { for(i = 0;i < w; i++) d[i] = f[s[i] - '0']; if(check(w)) ans++; } while(next_permutation(f,f + 4)); printf("%d\n",ans); return 0;} C.New Year and Curling水题123456789101112131415161718192021222324double fy[1005];int dx[1005];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,r,i,j; double y,yy; scanf("%d%d",&n,&r); for(i = 0;i < n; i++) { scanf("%d",&dx[i]); y = r; for(j = 0;j < i; j++) { if(abs(dx[i] - dx[j]) <= 2 * r) { yy = sqrt(4.0 * r * r - 1.0 * (dx[i] - dx[j]) * (dx[i] - dx[j])); y = max(y,fy[j] + yy); } } fy[i] = y; } for(i = 0;i < n; i++) printf("%.10f ",fy[i]); return 0;} D.New Year and Arbitrary Arrangement$f[i][j]$表示有$i$个$a$字符并且当前已经有$j$个$ab$序列的概率当$i+j >= k$的时候,再加一个$b$字符就肯定结束,可以直接推出加一个$b$字符产生的期望贡献所以$dp$总复杂度也就$k^{2}$1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x,int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x,int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a,int b) { int r = 1; while(b) { if(b & 1) r= mul(r,a); a = mul(a,a); b >>= 1; } return r;}int f[2005][2005];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int i,j,k,pa,pb,p,inv,w,ans = 0; scanf("%d%d%d",&k,&pa,&pb); p = pa + pb; inv = powt(p,mod - 2); w = add(mul(p,powt(pb,mod - 2)),mod - 1); f[1][0] = 1; for(i = 1;i <= 2000; i++) { for(j = 0;j <= 2000; j++) { if(f[i][j]) { if(i + j >= k) ans = add(ans,mul(f[i][j],add(i + j,w))); else { f[i + 1][j] = add(f[i + 1][j],mul(f[i][j],mul(pa,inv))); f[i][i + j] = add(f[i][i + j],mul(f[i][j],mul(pb,inv))); } } } } printf("%d\n",ans); return 0;} E.New Year and Entity Enumeration把状态相同的列放到一组,每组的答案就是非空集合的划分方案数,即贝尔数最后乘起来就好了123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a, int b) { int r = 1; while(b) { if(b & 1) r = mul(r, a); a = mul(a, a); b >>= 1; } return r;}char s[1005];char f[1005][55];int g[1005];int c[1005],b[1005];int C(int x,int y) { return mul(c[x],powt(mul(c[y],c[x - y]),mod - 2));}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int m, n, i, j; scanf("%d%d", &m, &n); c[0] = 1; for(i = 1;i <= m; i++) c[i] = mul(c[i - 1],i); b[0] = 1; for(i = 1;i <= m; i++) { for(j = 0;j < i; j++) b[i] = add(b[i],mul(b[j],C(i - 1,j))); } for(i = 0; i < n; i++) { scanf(" %s", s); for(j = 0; j < m; j++) f[j][i] = s[j]; } for(i = 0; i < m; i++) f[i][n] = 0; for(i = 0; i < m; i++) { for(j = 0; j < i; j++) { if(strcmp(f[i], f[j]) == 0) break; } g[j]++; } int ans = 1; for(i = 0;i < m; i++) { ans = mul(ans,b[g[i]]); } printf("%d\n", ans); return 0;} F.New Year and Rainbow Roads考虑每两个$G$相互独立,它们之间要么通过$B,R$相连,要么直接相连,两种情况讨论一下就行了12345678910111213141516171819202122232425262728293031323334int n, x, z, lr, lg, lb, mr, mb;char c;int main() {#ifdef CX_TEST //freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d %c", &x, &c); if (c == 'R' || c == 'G') { if (lr > 0) { z += x - lr; mr = max(mr, x - lr); } lr = x; } if (c == 'B' || c == 'G') { if (lb > 0) { z += x - lb; mb = max(mb, x - lb); } lb = x; } if (c == 'G') { if (lg > 0 && mr + mb > x - lg) { z += x - lg - mr - mb; } lg = x; mr = mb = 0; } } printf("%d\n", z); return 0;} G.New Year and Original Order考虑求出比$k$小的数字的个数有$j$个的数字的个数为$f[j][k]$把数字$k$的贡献拆成$k$个$1$那么$f[j][k]$对答案的贡献就是$f[j][k] * g[n - j],g[i]$是$i$个$1$ 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 705;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}void update(int &a, int b) { a += b; if(a >= mod) a -= mod;}char s[maxn];int a[maxn],p[maxn],g[maxn];int f[maxn][maxn][10][2];int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, i, j, k, l, ans = 0; scanf(" %s", s); n = strlen(s); for(i = p[0] = 1; i < maxn; i++) p[i] = mul(p[i - 1], 10); for(i = 1; i < maxn; i++) g[i] = add(g[i - 1], p[i - 1]); for(i = 0; i < n; i++) a[i] = s[i] - '0'; for(i = 1; i < 10; i++) f[0][0][i][0] = 1; for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { for(k = 1; k < 10; k++) { if(f[i][j][k][0]) { for(l = 0; l < a[i]; l++) update(f[i + 1][j + (l < k)][k][1], f[i][j][k][0]); update(f[i + 1][j + (a[i] < k)][k][0], f[i][j][k][0]); } if(f[i][j][k][1]) { for(l = 0; l < 10; l++) update(f[i + 1][j + (l < k)][k][1], f[i][j][k][1]); } } } } for(i = 0;i < n; i++) { for(k = 1;k < 10; k++) ans = add(ans,mul(g[n - i],add(f[n][i][k][0],f[n][i][k][1]))); } printf("%d\n", ans); return 0;} H.New Year and Boolean Bridges先连$A$,并查集维护,对于一个联通块,我们肯定要把它连成一个环如果一个联通块中存在两点的关系为$X$,肯定无解否则考虑把这些联通块合并一下,两个联通块之间的所有点对的关系都是$O$的话可以合并转化成$n/2$个点的图求最小的完全子图划分可以$fwt$维护但是由于我们只需要关注一个值的情况所以可以省去逆变换不如……直接上容斥吧……123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1 << 23;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x, int y) { LL z = 1LL * x * y; return z - z / mod * mod;}char s[55][55];int p[55], r[55], d[55], h[55], ans = 0;int f[maxn],g[maxn],bit[maxn];int ff(int x) { if(p[x] != x) p[x] = ff(p[x]); return p[x];}void funion(int x, int y) { x = ff(x); y = ff(y); if(x != y) p[y] = x;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, i, j; scanf("%d", &n); for(i = 0; i < n; i++) scanf(" %s", s[i]); for(i = 0; i < n; i++) p[i] = i; for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { if(i == j) continue; if(s[i][j] == 'A') funion(i, j); } } for(i = 0; i < n; i++) d[ff(i)]++; memset(h, -1, sizeof(h)); for(i = m = 0; i < n; i++) { if(d[i] > 1) h[i] = m++; } for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { if(i == j) continue; if(s[i][j] == 'X') { if(ff(i) == ff(j)) { return puts("-1"), 0; } if(d[ff(i)] > 1 && d[ff(j)] > 1) { r[h[ff(i)]] |= 1 << h[ff(j)]; r[h[ff(j)]] |= 1 << h[ff(i)]; } } } } if(!m) { printf("%d\n",n - 1); return 0; } for(i = 0;i < m; i++) r[i] ^= (1 << m) - 1; for(i = 0; i < (1 << m); i++) { if((i & (-i)) == i) f[i] = 1; else { j = i ^ (1 << (__builtin_ffs(i) - 1)); if(f[j] && (r[i] & j) == j) f[i] = 1; } g[i] = 1; bit[i] = ((m - __builtin_popcount(i)) & 1) ? mod - 1 : 1; } for (i = 0; i < m; i++) { for (j = 0; j < (1 << m); j++) { if ((j >> i) & 1) f[j] += f[j ^ (1 << i)]; } } for(i = 0;i < m; i++) { for(j = 0;j < (1 << m); j++) g[j] = mul(g[j],f[j]); int x = 0; for(j = 0;j < (1 << m); j++) x = add(x,mul(bit[j],g[j])); if(x) break; } printf("%d\n", n + i); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_Educational_Round_34_G]]></title>
<url>%2F2017%2F12%2F13%2FCF_edu34_G%2F</url>
<content type="text"><![CDATA[Yet Another Maxflow Problem题目传送门对于点$A_{i}$,它的流量有两种,一种是通过横边流向$B$,一种是流向$A_{i + 1}$.如果以$A_{i}$为分界点,那么答案就是$A$中$\leq i$的点通过横边流出的流量加上流向$A_{i + 1}$的流量.对于每个$A_{i}$,我们假设它流向$A_{i + 1}$是满流,然后通过线段树维护出$A$中$\leq i$的点通过横边实际流出的最大流量,令这两部分和为$c_{i}$.因为$A_{i}$实际流向$A_{i + 1}$的流量是$A_{i}->A_{i+1}$的边权和$A$中$> i$的点通过横边流出的流量中的最小值,所以答案就是$min(c_{i})$然后每次修改边权的时候只需要用线段树维护单点修改即可.1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 2e5 + 5;int ca[maxn];LL f[maxn * 4], ly[maxn * 4], cb[maxn], cc[maxn];struct edge { int u, v, w;} g[maxn];bool cmp(const edge &a, const edge &b) { return a.u < b.u;}void push_down(int t) { if(ly[t]) { f[t << 1] += ly[t]; ly[t << 1] += ly[t]; f[t << 1 | 1] += ly[t]; ly[t << 1 | 1] += ly[t]; ly[t] = 0; }}void build(int t, int l, int r, LL val[]) { ly[t] = 0; if(l == r) { f[t] = val[l]; return; } int mid = (l + r) >> 1; build(t << 1, l, mid, val); build(t << 1 | 1, mid + 1, r, val); f[t] = min(f[t << 1], f[t << 1 | 1]);}void update(int t, int l, int r, int ll, int rr, LL v) { if(ll <= l && r <= rr) { f[t] += v; ly[t] += v; return; } int mid = (l + r) >> 1; push_down(t); if(ll <= mid) update(t << 1, l, mid, ll, rr, v); if(rr > mid) update(t << 1 | 1, mid + 1, r, ll, rr, v); f[t] = min(f[t << 1], f[t << 1 | 1]);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n, m, q, i, j; scanf("%d%d%d", &n, &m, &q); for(i = 1; i < n; i++) scanf("%d%lld", &ca[i], &cb[i + 1]); build(1, 1, n, cb); for(i = 0; i < m; i++) scanf("%d%d%d", &g[i].u, &g[i].v, &g[i].w); sort(g, g + m, cmp); for(i = 1, j = 0; i <= n; i++) { while(j < m && g[j].u == i) { update(1, 1, n, 1, g[j].v, g[j].w); j++; } cc[i] = f[1] + ca[i]; } build(1, 1, n, cc); printf("%lld\n", f[1]); while(q--) { scanf("%d%d", &i, &j); update(1, 1, n, i, i, j - ca[i]); ca[i] = j; printf("%lld\n", f[1]); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[2017CCPC_final补]]></title>
<url>%2F2017%2F12%2F12%2F2017ccpc-final%2F</url>
<content type="text"><![CDATA[划水划水划水……然后就挂了…… D.Mr. Panda and Circles分三种情况讨论:两端都没有圆在线段外一端有圆在线段外两端都有圆在线段外……然后就是各种前缀和优化组合数求方案了第三种情况要用到任意模数的fft,然后还要写个前缀和减去自身卷积自身的情况……因为组合数太大了,所以还需要考虑单独维护模数的幂……123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x, int y) { x += y; if(x >= mod) x -= mod; return x;}int fmod(LL x) { return x - x / mod * mod;}int mul(int x, int y) { return fmod(1LL * x * y);}int powt(int a, int b) { int r = 1; while(b) { if(b & 1) r = mul(r, a); a = mul(a, a); b >>= 1; } return r;}int sqr(int x) { return fmod(1LL * x * x);}const int LN = 18;const int N = 1 << LN;const double pi = acos(-1.0);int fa[N], fb[N];struct Complex { double r, i; Complex(double r = 0.0, double i = 0.0): r(r), i(i) {}; Complex operator + (const Complex &rhs) { return Complex(r + rhs.r, i + rhs.i); } Complex operator - (const Complex &rhs) { return Complex(r - rhs.r, i - rhs.i); } Complex operator * (const Complex &rhs) { return Complex(r * rhs.r - i * rhs.i, i * rhs.r + r * rhs.i); } Complex conj() { return Complex(r, -i); }} wn[N];int bitrev[N];void fft_prepare() { for(int i = 0; i < N; i++) bitrev[i] = bitrev[i >> 1] >> 1 | ((i & 1) << (LN - 1)); for(int i = 0; i < N; i++) wn[i] = Complex(cos(2 * pi * i / N), sin(2 * pi * i / N));}void FFT(Complex a[], int l, int op) { int d = 0; while((1 << d) * l != N) d++; for(int i = 0; i < l; i++) { if(i < (bitrev[i] >> d)) swap(a[i], a[(bitrev[i] >> d)]); } for (int i = 2; i <= l; i <<= 1) { int lyc = N / i; for (int j = 0; j < l; j += i) { Complex *l = a + j, *r = a + j + (i >> 1), *p = wn; for(int k = 0; k < (i >> 1); k++) { Complex tmp = *r * *p; *r = *l - tmp, *l = *l + tmp; ++l, ++r, p += lyc; } } } if(op == -1) { for(int i = 0; i < l; i++) { a[i].r /= l; a[i].i /= l; } }}Complex va[N], vb[N], da[N], db[N], dd[N];void Conv(int fa[], int fc[], int l) { int i; for(i = 0; i < l; i++) va[i] = Complex(fa[i] & 32767, fa[i] >> 15); FFT(va, l, 1); for(i = 0; i < l; i++) { int j = (l - i) & (l - 1); Complex qa, qb, qc, qd; qa = (va[i] + va[j].conj()) * Complex(0.5, 0.0); qb = (va[i] - va[j].conj()) * Complex(0.0, -0.5); da[j] = qa * qa; db[j] = qa * qb; dd[j] = qb * qb; } for(i = 0; i < l; i++) va[i] = da[i] + db[i] * Complex(0.0, 1.0); for(i = 0; i < l; i++) vb[i] = db[i] + dd[i] * Complex(0.0, 1.0); FFT(va, l, -1); FFT(vb, l, -1); for(i = 0; i < l; i++) { int wa = fmod(va[i].r + 0.5); int wb = fmod(va[i].i + 0.5); int wc = fmod(vb[i].r + 0.5); int wd = fmod(vb[i].i + 0.5); fc[i] = add(wa, add(fmod(((LL)add(wb, wc)) << 15), fmod(((LL)wd) << 30))); }}struct node { int res, cnt; void init(LL a, LL b) { res = 1; cnt = 0; while(a <= b) { int c = fmod(a); if(c == 0) cnt++; else res = mul(res, c); a++; } } int val() { return cnt ? 0 : res; } void add(LL x) { x = fmod(x); if(x == 0) cnt++; else res = mul(res, x); } void del(LL x) { x = fmod(x); if(x == 0) cnt--; else res = mul(res, powt(x, mod - 2)); }} fac;int a[maxn], r[maxn];int solve() { int n, i, x, y, l, rmax = 0, ans = 0; P u; LL m, d, s = 0; scanf("%d%lld", &n, &m); for(i = 0; i < n; i++) { scanf("%d", &a[i]); s += a[i]; rmax = max(rmax, a[i]); } s *= 2; d = m - 1 - s; // step1 if(d > 0) { fac.init(d + 1, d + n); ans = add(ans, mul(sqr(fmod(d)), fac.val())); } // step2 memset(r, 0, sizeof(r)); for(i = 0; i < n; i++) r[a[i]]++; for(i = 100000; i > 0; i--) r[i] += r[i + 1]; i = min(max(0LL, -d), 200000LL); fac.init(d + i + 1, d + i + n - 1); for(i = i + 1, y = 0; i <= 100000; i++) { fac.add(d + i + n - 1); fac.del(d + i); if(r[i]) y = add(y, mul(r[i], mul(fac.val(), sqr(fmod(d + i))))); } ans = add(ans, mul(y, 2)); // step3 if(n == 1) return ans; for(l = 1; l <= (rmax << 1); l <<= 1); memcpy(fa, r, sizeof(r)); if(l > maxn) fill(fa + maxn,fa + l,0); Conv(fa, fb, l); memset(fa, 0, sizeof(fa)); for(i = 0; i < n; i++) { fa[2]++; fa[a[i] + 2] -= 2; fa[(a[i] << 1) + 2]++; } for(x = y = i = 0; i < l; i++) { x = add(x, mod + fa[i]); y = add(x, y); fb[i] = add(fb[i], mod - y); } i = min(max(0LL, -d), 500000LL); fac.init(d + i + 1, d + i + n - 2); for(i = i + 1; i < l; i++) { fac.add(d + i + n - 2); fac.del(d + i); if(fb[i]) ans = add(ans, mul(fb[i], mul(fac.val(), sqr(fmod(d + i))))); } return ans;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t, i; fft_prepare(); scanf("%d", &t); for(i = 1; i <= t; i++) printf("Case #%d: %d\n", i, solve()); return 0;} F.Fair Lottery把等式转化成不等式,直接线性规划莽……不过这个单纯形的板子过不了uoj179的$hack$数据…………似乎没有太大影响?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int maxn = 1050;const double eps = 1e-8;struct Simplex { int n, m; int idx[maxn], idy[maxn]; double a[maxn][maxn], ans[maxn]; void init(int _n, int _m) { n = _n; m = _m; for(int i = 0; i <= n; i++) idx[i] = i; for(int i = 1; i <= m; i++) idy[i] = i + n; } void pivot(int u, int v) { swap(idx[v], idy[u]); double t = a[u][v]; a[u][v] = 1.0; for(int i = 0; i <= n; i++) a[u][i] /= t; for(int i = 0; i <= m; i++) { if(i == u || fabs(a[i][v]) < eps) continue; t = a[i][v]; a[i][v] = 0; for(int j = 0; j <= n; j++) a[i][j] -= a[u][j] * t; } } bool init_check() { while(true) { int u = 0, v = 0; double mn = -eps; for(int i = 1; i <= m; i++) { if(a[i][0] < mn && (!u || (rand() & 1))) { mn = a[i][0]; u = i; } } if(!u) return true; mn = -eps; for(int i = 1; i <= n; i++) { if(a[u][i] < mn && (!v || (rand() & 1))) { mn = a[u][i]; v = i; } } if(!v) return false; pivot(u, v); } } bool do_simplex() { while(true) { int u = 0, v = 0; double mn = 1e15, mx = eps; for(int i = 1; i <= n; i++) { if(a[0][i] > mx && (!v || (rand() & 1))) { mx = a[0][i]; v = i; } } if(!v) return true; for(int i = 1; i <= m; i++) { if(a[i][v] > eps && a[i][0] / a[i][v] < mn) { mn = a[i][0] / a[i][v]; u = i; } } if(!u) return false; pivot(u, v); } } void get_ans() { memset(ans, 0, sizeof(ans)); ans[0] = -a[0][0]; for(int i = 1; i <= m; i++) { if(idy[i] <= n) ans[idy[i]] = a[i][0]; } }} sf;int d[15], f[12][1050];double solve() { int n, m, i, j, x, tot = 0; scanf("%d%d", &n, &m); for(i = 0; i < n; i++) scanf("%d", &d[i]); memset(f, 0, sizeof(f)); for(i = 0; i < (1 << n); i++) { for(j = x = 0; j < n; j++) { if((i >> j) & 1) x += d[j]; } if(x <= m) { tot++; for(j = 0; j < n; j++) { if((i >> j) & 1) f[j][tot] = 1; } } } sf.init(tot, n + 2); for(i = 0;i <= tot; i++) sf.a[0][i] = f[0][i]; for(i = 1;i < n; i++) { for(j = 0;j <= tot; j++) sf.a[i][j] = f[i][j] - f[i - 1][j]; } for(j = 0;j <= tot; j++) sf.a[n][j] = f[0][j] - f[n - 1][j]; for(j = 1;j <= tot; j++) { sf.a[n + 1][j] = 1; sf.a[n + 2][j] = -1; } sf.a[n + 1][0] = 1; sf.a[n + 2][0] = -1; sf.init_check(); sf.do_simplex(); return -sf.a[0][0];}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif srand(time(NULL)); int t, i; scanf("%d", &t); for(i = 1; i <= t; i++) printf("Case #%d: %.10f\n", i, solve()); return 0;} H.Equidistance先求出$m-1$个线性无关的基向量,然后随机一个向量尝试把这组基向量扩展到满秩即可…… 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const double eps = 1e-8;inline sgn(double x) { if(x < -eps) return -1; else if(x > eps) return 1; else return 0;}int n, m;struct Point { vector<double> a; Point operator +(const Point &b) const { Point c; c.a.resize(n); for(int i = 0; i < n; i++) c.a[i] = a[i] + b.a[i]; return c; } Point operator -(const Point &b) const { Point c; c.a.resize(n); for(int i = 0; i < n; i++) c.a[i] = a[i] - b.a[i]; return c; } double operator *(const Point &b) const { double res = 0; for(int i = 0; i < n; i++) res += a[i] * b.a[i]; return res; } Point operator *(const double &b) const { Point c = *this; for(int i = 0; i < n; i++) c.a[i] *= b; return c; }} p[105], f[105], s, us;uniform_real_distribution<double> df(-100, 100);default_random_engine gen(time(NULL));Point work() { Point x; x.a.resize(n); while(true) { for(int i = 0; i < n; i++) x.a[i] = df(gen); for(int i = 1; i < m; i++) { double u = x * f[i]; x = x - f[i] * u; } if((x * x) > eps) return x; }}void solve() { int i, j; double u; scanf("%d%d", &n, &m); printf("%d\n", n + 1 - m); s.a.clear(); s.a.resize(n,0); for(i = 0; i < m; i++) { p[i].a.resize(n); for(j = 0; j < n; j++) scanf("%lf", &p[i].a[j]); s = s + p[i]; } us = s * (1.0 / m); for(i = 1; i < m; i++) { f[i] = p[i] - us; for(j = 1; j < i; j++) { u = f[i] * f[j]; f[i] = f[i] - f[j] * u; } u = sqrt(f[i] * f[i]); f[i] = f[i] * (1.0 / u); } while(m < n + 1) { p[m] = work(); u = sqrt(p[m] * p[m]); double v = sqrt(1.0 - (p[0] - us) * (p[0] - us)); p[m] = p[m] * (v / u) + us; for(i = 0; i < n; i++) printf("%.10f%c", p[m].a[i], " \n"[i + 1 == n]); f[m] = p[m] - us; u = sqrt(f[m] * f[m]); f[m] = f[m] * (1.0 / u); s = s + p[m]; us = s * (1.0 / (++m)); }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int i, t; scanf("%d", &t); for(i = 1; i <= t; i++) { printf("Case #%d: ", i); solve(); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#449(Div. 1)简单题解]]></title>
<url>%2F2017%2F12%2F08%2FCF-449%2F</url>
<content type="text"><![CDATA[题目传送门 A.Nephren gives a riddle水题……12345678910111213141516171819202122232425262728293031323334353637383940414243444546//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;char s0[] = "What are you doing at the end of the world? Are you busy? Will you save us?";char s1[] = "What are you doing while sending \"";char s2[] = "\"? Are you busy? Will you send \"";char s3[] = "\"?";LL f[maxn],mm = 1e18 + 1e5;char solve(int n,LL k) { if(f[n] < k) return '.'; if(n == 0) return s0[k - 1]; if(k <= strlen(s1)) return s1[k - 1]; k -= strlen(s1); if(k <= f[n - 1]) return solve(n - 1,k); k -= f[n - 1]; if(k <= strlen(s2)) return s2[k - 1]; k -= strlen(s2); if(k <= f[n - 1]) return solve(n - 1,k); k -= f[n - 1]; return s3[k - 1];}int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int i,q,n; LL k; f[0] = strlen(s0); for(i = 1;i < maxn; i++) f[i] = min(mm,(LL)strlen(s1) + (LL)strlen(s2) + (LL)strlen(s3) + f[i - 1] * 2); scanf("%d",&q); while(q--) { scanf("%d%lld",&n,&k); printf("%c",solve(n,k)); } return 0;} B.Ithea Plays With Chtholly从左到右和从右到左分别维护一个单调队列……那么入队次数最多也就最多$\frac{nc}{2}$次,就像一个直角三角形的两个锐角向直角延伸的样子……1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;vector<int> l,r;int n;void solvel(int x) { if(l.empty() || l.back() <= x) { l.push_back(x); printf("%d\n",(int)l.size()); } else { int d = upper_bound(l.begin(),l.end(),x) - l.begin(); l[d] = x; printf("%d\n",d + 1); }}void solver(int x) { if(r.empty() || r.back() >= x) { r.push_back(x); printf("%d\n",n - (int)r.size() + 1); } else { int d; for(d = 0;d < r.size(); d++) if(r[d] < x) break; r[d] = x; printf("%d\n",n - d); }}int main(){#ifdef CX_TEST //freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int m,c,i,x; scanf("%d%d%d",&n,&m,&c); while(1) { scanf("%d",&x); if(x * 2 <= c) solvel(x); else solver(x); fflush(stdout); if(l.size() + r.size() == n) break; } return 0;} C.Willem, Chtholly and Seniorious因为操作纯随机,所以2操作不会太少,而得到的区间的期望长度是$\frac{n}{3}$,所以操作一定次数后只有较少的值不同的区间,所以暴力维护就好了123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;typedef pair<LL,int> PL;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x,int y,int m) { x += y; if(x >= m) x -= m; return x;}int mul(int x,int y,int m) { LL z = 1LL * x * y; return z - z / m * m;}int powt(int a,int b,int m) { int r = 1; while(b) { if(b & 1) r = mul(r,a,m); a = mul(a,a,m); b >>= 1; } return r;}LL a[maxn];int seed,vmax;set<P> q;vector<P> f;vector<PL> g;int rnd() { int u = seed; seed = add(mul(seed,7,mod),13,mod); return u;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,m,i,j,op,x,y,l,r; scanf("%d%d%d%d",&n,&m,&seed,&vmax); for(i = 1; i <= n; i++) a[i] = rnd() % vmax + 1; for(i = j = 1; i <= n; i = j) { while(a[j] ==a[i]) j++; q.insert(P(j - 1,i)); } for(i = 1; i <= m; i++) { op = (rnd() & 3) + 1; l = rnd() % n + 1; r = rnd() % n + 1; if(l > r) swap(l,r); auto e = q.lower_bound(P(l,0)); if(op == 3) { x = rnd() % (r - l + 1) + 1; g.clear(); if(r <= (*e).first) { printf("%lld\n",a[(*e).first]); continue; } while(e != q.end() && (*e).second <= r) { g.push_back(PL(a[(*e).first],min((*e).first,r) - max((*e).second,l) + 1)); e++; } sort(g.begin(),g.end()); for(auto w:g) { x -= w.second; if(x <= 0) { printf("%lld\n",w.first); break; } } } else { x = rnd() % vmax + 1; j = 0; if(op == 4) { y = rnd() % vmax + 1; while(e != q.end() && (*e).second <= r) { //cout<<a[(*e).first]<<" "<<min((*e).first,r) - max((*e).second,l) + 1<<endl; j = add(j,mul(powt(a[(*e).first] % y,x,y),min((*e).first,r) - max((*e).second,l) + 1,y),y); e++; } printf("%d\n",j); } else { f.clear(); while(e != q.end() && (*e).second <= r) { f.push_back(*e); e++; } if(op == 1) { for(auto u:f) { q.erase(u); if(u.first > r) q.insert(P(u.first,r + 1)); if(u.second < l) { q.insert(P(l - 1,u.second)); a[l - 1] = a[u.first]; } q.insert(P(min(u.first,r),max(u.second,l))); a[min(u.first,r)] = a[u.first] + x; } } else { for(auto u:f) { q.erase(u); if(u.first > r) q.insert(P(u.first,r + 1)); if(u.second < l) { q.insert(P(l - 1,u.second)); a[l - 1] = a[u.first]; } } q.insert(P(r,l)); a[r] = x; } } } } return 0;} D.Nephren Runs a Cinema固定VIP的人数,剩下的等价于括号匹配方案数,考虑卡特兰数和组合数的那个关系式就好了?似乎以前都没注意过那个式子呀因为模数不是质数,所以仿照扩展卢卡斯一样,用CRT合并就可以了 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<LL,LL> P;typedef pair<LL,LL> PL;const LL mod = 1e9 + 7;const LL maxn = 1e5 + 5;LL add(LL x,LL y,LL m) { x += y; if(x >= m) x -= m; return x;}LL mul(LL x,LL y,LL m) { LL z = 1LL * x * y; return z - z / m * m;}LL powt(LL a,LL b,LL m) { LL r = 1; while(b) { if(b & 1) r = mul(r,a,m); a = mul(a,a,m); b >>= 1; } return r;}void extend_Euclid(LL a, LL b, LL &x, LL &y) { if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); LL tmp = x; x = y; y = tmp - (a / b) * y;}LL Inv(LL a,LL b) { LL x,y; extend_Euclid(a,b,x,y); return (x % b + b) % b;}LL CRT(vector<LL> &a,vector<LL> &m,LL M) { LL ans = 0,n = a.size(); for(LL i = 0; i < n; i++) { LL x,y; LL Mi = M / m[i]; extend_Euclid(Mi, m[i], x, y); x = (x % M + M) % M; ans = add(ans,mul(mul(Mi,x,M),a[i],M),M); } return ans;}map<LL,LL> fac;vector<LL> fa,fm;struct node { LL u,t,p; LL f[maxn],g[maxn]; void init(LL a,LL b) { LL i,x; u = a; t = b; p = powt(a,b,mod * 2); for(i = f[0] = 1;i <= 100000; i++) { for(x = i;x % u == 0; x /= u); f[i] = mul(f[i - 1],x,p); } memset(g,0,sizeof(g)); for(i = 1;i * u <= 100000; i++) g[i * u] = g[i] + 1; for(i = 1;i <= 100000; i++) g[i] += g[i - 1]; } LL get_mul(LL n,LL m) { if(m < 0 || n < m) return 0; LL tc = g[n] - g[m] - g[n - m]; if(tc >= t) return 0; return mul(powt(u,tc,mod * 2),mul(f[n],Inv(mul(f[m],f[n - m],p),p),p),p); }} fs[20];LL tot = 0;void init(LL n) { for(LL i = 2; i * i <= n; i++) { while(n % i == 0) { fac[i]++; n /= i; } } if(n > 1) fac[n]++; for(auto e:fac) { fs[tot].init(e.first,e.second); fm.push_back(fs[tot++].p); }}LL cal(LL n,LL m,LL p) { fa.clear(); for(LL i = 0;i < tot; i++) fa.push_back(fs[i].get_mul(n,m)); return CRT(fa,fm,p);}LL solve(LL n,LL k,LL l,LL r,LL p) { if(k + l > n) return 0; LL ans = cal(n,k,p); n -= k; r = min(r,n); if((n - r) & 1) r--; if((n - l) & 1) l++; r += 2; LL d = cal(n,(n - l) >> 1,p); if(r <= n) d = add(d,p - cal(n,(n - r) >> 1,p),p); return mul(ans,d,p);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,p,l,r,ans = 0; scanf("%d%d%d%d",&n,&p,&l,&r); init(p); for(LL i = 0;i <= n; i++) ans = add(ans,solve(n,i,l,r,p),p); printf("%d\n",ans); return 0;} E.Welcome home, Chtholly直接暴力一波即可过分块,对于整个块的1操作,维护块内的最大最小值$v_{max},v_{min}$,如果$v_{min} + x + x \leq v_{max}$,把小于$x$的数加上$x$然后整个块减$x$即可,否则就把大于$x$的数暴力维护减去$x$的数加上$x$然后整个块减$x$即可因为这样做是一直在缩小区间,并且每个值只会访问一次,所以可以保证对于一个块的总操作次数是$O(n)$的为了实现这样的操作,需要用并查集维护每个数被修改后变成了哪个值,因为每次并查集修改后指向的值都是上述操作未被访问过的值,所以不会存在重叠或循环的问题…… 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int, int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;const int bsize = 340;struct block { int d[maxn], p[maxn], l, r; void add(int x) { d[x]++; r = max(x, r); } int ff(int x) { if(p[x] == 0) p[x] = x; if(p[x] != x) p[x] = ff(p[x]); return p[x]; } void update(int x) { if(x + l > r) return; if(l + x + x <= r) { for(int i = l + 1; i <= l + x; i++) { if(d[i]) { d[i + x] += d[i]; d[i] = 0; p[i] = i + x; } } l += x; } else { for(int i = l + x + 1; i <= r; i++) { if(d[i]) { d[i - x] += d[i]; d[i] = 0; p[i] = i - x; } } r = l + x; } } int query(int x) { if(x + l > r) return 0; else return d[x + l]; }} f[bsize];int a[maxn], id[maxn], n;void rebuild(int k, int l, int r, int x) { for(int i = l; i <= r; i++) { a[i] = f[k].ff(a[i]); if(a[i] > x + f[k].l) { f[k].d[a[i]]--; a[i] -= x; f[k].d[a[i]]++; } }}int query(int k, int l, int r, int x) { int t = 0; for(int i = l; i <= r; i++) { if(f[k].ff(a[i]) == x + f[k].l) t++; } return t;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int m, i, j, k, op, l, r, x; scanf("%d%d", &n, &m); for(i = 1, j = k = 0; i <= n; i++) { scanf("%d", &a[i]); id[i] = k; f[k].add(a[i]); if(++j == bsize) { j = 0; k++; } } while(m--) { scanf("%d%d%d%d", &op, &l, &r, &x); if(op == 1) { if(id[l] == id[r]) rebuild(id[l], l, r, x); else { rebuild(id[l], l, (id[l] + 1) * bsize, x); rebuild(id[r], id[r] * bsize + 1, r, x); for(i = id[l] + 1; i < id[r]; i++) f[i].update(x); } } else { if(id[l] == id[r]) k = query(id[l], l, r, x); else { k = query(id[l], l, (id[l] + 1) * bsize, x); k += query(id[r], id[r] * bsize + 1, r, x); for(i = id[l] + 1; i < id[r]; i++) k += f[i].query(x); } printf("%d\n", k); } } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[假如我们能够从头再来]]></title>
<url>%2F2017%2F12%2F04%2F20171204%2F</url>
<content type="text"><![CDATA[哈尔滨的寒风……就这么吹进了心里…… 听着熟悉的歌,想到了熟悉的人,一种孤独感突然就那么蔓延了开来想要忆起一些过往,却发现自己似乎没有什么太深刻的过往呢……大学生涯变得越来越单调了,失去的东西好像也越来越多了。之前还能绷紧神经过着充实的训练和补题,现在突然就感觉那是多么的累,亦有一种无可奈何的凄凉感,无论再怎么做,总会有一些东西不会,永远的做不完……永远的学不全……而且,每次盯着屏幕上那昂贵的票价时的望洋兴叹,每次为了寻找一个便宜了几十块钱的辗转多次的线路时的纠结,都让我感觉好烦好累… 当初我选择acm的原因是什么呢?似乎已经记不得了,好像也没有什么特别的原因吧,可能是带着高中的一些遗憾,可能是众多竞赛中只有它我比较熟悉吧(虽然也是在大学才知道的acm)……不管是因为什么,选了就会努力做好它……似乎自己确实做得不太好,总会掉一下链子。每当感觉自己现在这个样子还不错的时候,总是会遇到一些神奇的题,把我打回原形,然后又不停的补题,学习一些新套路……但是,学了这么多,即使会做很多人难题,却总是感觉缺了些什么,似乎只会运用,当自己想构思一个好思路时,却总是想不出什么东西,给自己一种半吊子的感觉。 组队的时候也感觉自己发不出力来……明明感觉自己的能力是可以carry的,却时不时变成划水选手,虽然这里面还有其它的因素,但是总不该是这样的…… 以上或许都是无病呻吟吧……反正明天还是会和往常一样,打开熟悉的网页,做着千奇百怪的题……今年又要结束了呀……题目是什么,随便取一个吧]]></content>
</entry>
<entry>
<title><![CDATA[无名]]></title>
<url>%2F2017%2F12%2F02%2F20171202%2F</url>
<content type="text"><![CDATA[喂,你敢喜欢我吗(飞碟说)你……我…… 一梦醒,一梦空…… 2017.12.10 +1]]></content>
</entry>
<entry>
<title><![CDATA[Byteland_Trip]]></title>
<url>%2F2017%2F11%2F30%2Fgym-101611B%2F</url>
<content type="text"><![CDATA[题目传送门题意:略……$l[i][j]$表示从左边开始的前$i$个字符组成$j$个向右的半环的方案数.$r[i][j]$表示从右边开始的前$i$个字符组成$j$个向左的半环的方案数.然后就可以愉快的转移了……然后就可以枚举终点愉快的统计答案了……12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 5005;void add(int &x,int y) { x += y; if(x >= mod) x -= mod;}int mul(int x,int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int p[maxn],l[maxn][maxn],r[maxn][maxn];char s[maxn];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,i,j; scanf("%s",s); n = strlen(s); for(p[0] = i = 1;i <= n; i++) p[i] = mul(i,p[i - 1]); if(n == 1) return puts("1"); l[1][1] = (s[0] == '>'); for(i = 1;i < n; i++) { for(j = 1;j <= i; j++) add(l[i + 1][j],mul(l[i][j],j)); if(s[i] == '<') { for(j = 2;j <= i; j++) add(l[i + 1][j - 1],mul(l[i][j],mul(j,j - 1))); } else { for(j = 1;j <= i; j++) add(l[i + 1][j + 1],l[i][j]); } } reverse(s,s + n); r[1][1] = (s[0] == '<'); for(i = 1;i < n; i++) { for(j = 1;j <= i; j++) add(r[i + 1][j],mul(r[i][j],j)); if(s[i] == '>') { for(j = 2;j <= i; j++) add(r[i + 1][j - 1],mul(r[i][j],mul(j,j - 1))); } else { for(j = 1;j <= i; j++) add(r[i + 1][j + 1],r[i][j]); } } for(i = 1;i <= n; i++) { if(i == 1) printf("%d ",r[n - 1][1]); else if(i == n) printf("%d ",l[n - 1][1]); else { int ans = 0; for(j = 1;j < i; j++) { add(ans,mul(mul(mul(l[i - 1][j],r[n - i][j]),mul(p[j],p[j])),2)); add(ans,mul(mul(l[i - 1][j],r[n - i][j + 1]),mul(p[j],p[j + 1]))); add(ans,mul(mul(l[i - 1][j + 1],r[n - i][j]),mul(p[j],p[j + 1]))); } printf("%d ",ans); } } puts(""); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[hihocoder1635_Colored_Nodes]]></title>
<url>%2F2017%2F11%2F30%2Fbeijing-icpc-i%2F</url>
<content type="text"><![CDATA[题目传送门题意:略……暴力染色一轮,然后可以得到每个点的颜色是从哪个点转移过来的,类似于等到了一个点的颜色转移矩阵.如果点$i$的前驱是$fa_{i}$,则连边$fa_{i}->i$,然后可以得到一些基环外向树,可以知道每棵树只有一个环,树上的点的颜色会被环上的点等频率的染色到.然后把每棵树重新定义一种颜色,模拟一轮染色,就可以得到这棵树在一轮染色中占有了的点的个数.一轮染色染$n$次,总共$n^{2}$个点.那么每棵树的答案即是$\frac{sum}{num * n}$,$sum$为占有的点的个数,$num$为环上点的个数.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;vector<int> g[maxn];vector<double> ans;int c[maxn],d[maxn],pre[maxn],cnum[maxn],tot,col;LL csum[maxn];int dfs(int u) { if(d[u] == -1) { d[u] = col++; cnum[d[u]]++; return u; } else if(d[u]) return 0; d[u] = -1; int dx = dfs(c[u]); d[u] = d[c[u]]; if(dx == 0 || dx == u) return 0; else { cnum[d[u]]++; return dx; }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,m,i,u,v; while(~scanf("%d%d",&n,&m)) { for(i = 1; i <= n; i++) { g[i].clear(); c[i] = i; } memset(pre,0,sizeof(pre)); memset(d,0,sizeof(d)); memset(csum,0,sizeof(csum)); memset(cnum,0,sizeof(cnum)); ans.clear(); for(i = 0; i < m; i++) { scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } for(i = 1; i <= n; i++) { for(auto x:g[i]) c[x] = c[i]; } for(i = col = 1; i <= n; i++) { if(!d[i]) dfs(i); } for(i = 1; i <= n; i++) { for(auto x:g[i]) { if(d[x] != d[i]) { csum[d[x]] += i - pre[x]; d[x] = d[i]; pre[x] = i; } } } for(i = 1; i <= n; i++) csum[d[i]] += n - pre[i]; for(i = 1; i < col; i++) { double fs = 1.0 * csum[i] / n / cnum[i]; for(v = 0; v < cnum[i]; v++) ans.push_back(fs); } sort(ans.rbegin(),ans.rend()); for(auto x:ans) printf("%.6f\n",x); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[F.Fygon_2.0]]></title>
<url>%2F2017%2F11%2F28%2F2017_NEERC_F%2F</url>
<content type="text"><![CDATA[题意: 给你一些$for$的嵌套表达式,求渐近复杂度分析: 如果是$for(i:1->n) for(j:i->n) for(k:j->n) \dots$的形式,那么我们可以知道其复杂度是$\frac{n^{m}}{m!}$,然而其它的表达式形式都可以拆成多个这样的形式的和,那么就转化为能有多少组这样的形式,如果把给的$for(a:b->c)$转换为两条边$b->a,a->c$,那么就变成图的拓扑序个数,当然我们可能遇到环,把环缩点掉就好了(因为环表示环上所有点的值都相同) 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int,int> P;map<char,int> q;int tot = 0;int fa[22],h[22],g[22][22];LL f[1 << 20];int get_id(char x) { if(x == '1' || x == 'n') return -1; if(!q.count(x)) q[x] = tot++; return q[x];}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif freopen("fygon20.in", "r", stdin); freopen("fygon20.out", "w", stdout); int n,i,j,k,u,l,r; char s[22]; scanf("%d",&n); for(i = 1;i < n; i++) { scanf("%s",s); scanf("%s",s); u = get_id(s[0]); scanf("%s",s); scanf("%s",s); l = get_id(s[6]); scanf("%s",s); r = get_id(s[0]); if(~l) fa[u] |= 1 << l,g[l][u] = 1; if(~r) fa[r] |= 1 << u,g[u][r] = 1; } for(i = 0;i < tot; i++) { for(j = 0;j < tot; j++) { for(k = 0;k < tot; k++) g[j][k] |= g[j][i] & g[i][k]; } } n--; for(i = 0;i < tot; i++) { if(h[i] == -1) continue; h[i] |= 1 << i; for(j = i + 1;j < tot; j++) { if(g[i][j] && g[j][i]) { h[i] |= 1 << j,h[j] = -1; n--; fa[i] |= fa[j]; } } fa[i] ^= fa[i] & h[i]; } f[0] = 1; for(i = 0;i < (1 << tot); i++) { if(f[i]) { for(j = 0;j < tot; j++) { if(!((i >> j) & 1) && ((i & fa[j]) == fa[j])) f[i | h[j]] += f[i]; } } } LL a = 1,b = f[(1 << tot) - 1]; for(i = 2;i <= n; i++) a *= i; LL g = __gcd(a,b); printf("%d %lld/%lld\n",n,b / g,a / g); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[hihocoder1629_Graph]]></title>
<url>%2F2017%2F11%2F23%2Fbeijing-icpc-c%2F</url>
<content type="text"><![CDATA[题目传送门题意: 给你一个带标号的无向图,有$q$次询问,每次询问区间$[L,R]$内有多少对点联通并且该路径上所有点都在这个区间内.按端点从小到大的顺序加边,每条边加两次,然后能得到一个边序列,同时能处理出每个点所属的边的区间$[l_{i},r_{i}]$,对于一个询问$[L,R]$,即询问边序列上区间$[l_{L},r_{R}]$内两个端点都在$[L,R]$内的那些边组成的图的答案.然后把这个边序列分块,用类似莫队的思想处理询问,只是把减操作变成了还原操作,用按秩合并的并查集维护联通块个数即可.123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126//created by missever#include<bits/stdc++.h>#define fi first#define se secondusing namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;const int b_size = 333;P p[maxn];vector<int> g[maxn];int l[maxn],r[maxn],id[maxn],lim[maxn];LL ans[maxn];struct que { int l,r,id;} fq[maxn];bool cmp(const que &a,const que &b) { if(id[l[a.l]] == id[l[b.l]]) return r[a.r] < r[b.r]; else return id[l[a.l]] < id[l[b.l]];}struct union_find { int f[maxn],rk[maxn],num[maxn],tot; P res[maxn]; LL ans; void init(int n) { for(int i = 0; i <= n; i++) f[i] = i,rk[i] = num[i] = 1; ans = tot = 0; } int ff(int x) { while(f[x] != x) x = f[x]; return x; } void do_union(int x,int y) { x = ff(x); y = ff(y); if(x == y) return; if(rk[x] < rk[y]) swap(x,y); res[tot++] = P(y,rk[x]); f[y] = x; ans += 1LL * num[x] * num[y]; num[x] += num[y]; rk[x] = max(rk[x],rk[y] + 1); } void back(int m) { int x,y; while(tot > m) { tot--; y = res[tot].fi; x = f[y]; rk[x] = res[tot].se; num[x] -= num[y]; ans -= 1LL * num[x] * num[y]; f[y] = y; } }} uf;void solve() { int n,m,q,i,j,pre,k,x,y; scanf("%d%d%d",&n,&m,&q); for(i = 1; i <= n; i++) g[i].clear(); for(i = 0; i < m; i++) { scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } for(i = 1,m = -1;i <= n; i++) { l[i] = m + 1; for(auto v:g[i]) { if(v > i) p[++m] = P(i,v); else p[++m] = P(v,i); lim[m] = i; } r[i] = m; } for(i = j = 0,k = 1;i <= m; i++) { if(++j == b_size) k++,j = 0; id[i] = k; } for(i = 0; i < q; i++) { scanf("%d%d",&fq[i].l,&fq[i].r); fq[i].id = i; } sort(fq,fq + q,cmp); i = 0; while(i < q) { k = id[l[fq[i].l]]; uf.init(n); pre = 0; x = y = min(k * b_size,m + 1); while(i < q && id[l[fq[i].l]] == k) { if(id[r[fq[i].r]] <= k) { for(j = l[fq[i].l];j <= r[fq[i].r]; j++) { if(fq[i].l <= p[j].fi && p[j].se <= fq[i].r) uf.do_union(p[j].fi,p[j].se); } } else { while(x <= r[fq[i].r]) { if(lim[y] <= p[x].fi && p[x].se <= fq[i].r) uf.do_union(p[x].fi,p[x].se); x++; } pre = uf.tot; for(j = l[fq[i].l];j < y; j++) { if(fq[i].l <= p[j].fi && p[j].se <= fq[i].r) uf.do_union(p[j].fi,p[j].se); } } ans[fq[i++].id] = uf.ans; uf.back(pre); } } for(i = 0;i < q; i++) printf("%lld\n",ans[i]);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; scanf("%d",&t); while(t--) solve(); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#446(Div. 1)_E]]></title>
<url>%2F2017%2F11%2F22%2FCF_446_E%2F</url>
<content type="text"><![CDATA[题目传送门题意: 给你一个序列并执行$k$次操作,每次选择一个数减一,并给$res$加上其它数的乘积,求最后$res$的期望值分析: 思考一下就会发现,对于每种操作方案,最后的$res$都是初始序列各数的乘积减去操作完后各数乘积.所以最后的期望答案就是$ans = \prod_{i=1}^{n}a_{i} - k!/ n^{k} \sum_{\sum_{i=1}^{n}x_{i}=k}\prod_{i=1}^{n}(a_{i} - x_{i})/x_{i}!$我们可以发现上述式子中存在一个卷积,并且存在分母为阶乘的分式,那么就可以很自然的想到指数型生成函数.因为$\sum (a_{i} - j)x^{j}/j!=(a_{i} - x)e^{x}$,所以有$ans=\prod_{i=1}^{n}a_{i} - k!/ n^{k}e^{nx}\prod_{i=1}^{n}(a_{i} - x)$,我们只需要求出这个生成函数的第$x^{k}$项的系数即可.通过$n^{2}$暴力求解最右边的连乘,然后枚举连乘部分所占的指数系数大小即可求得答案.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x,int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x,int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int powt(int a,int b) { int r = 1; while(b) { if(b & 1) r = mul(r,a); a = mul(a,a); b >>= 1; } return r;}int a[5005],f[5005];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,k,i,j,u,s,ans = 0; scanf("%d%d",&n,&k); for(i = 0,s = f[0] = 1;i < n; i++) { scanf("%d",&a[i]); s = mul(s,a[i]); for(j = i;j >= 0; j--) { f[j + 1] = add(f[j + 1],mod - f[j]); f[j] = mul(f[j],a[i]); } } for(i = 0,u = 1;i <= min(k,n); i++) { ans = add(ans,mul(mul(u,f[i]),powt(n,k - i))); u = mul(u,k - i); } ans = add(s,mod - mul(ans,powt(powt(n,k),mod - 2))); printf("%d\n",ans); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#443(Div. 1)_E]]></title>
<url>%2F2017%2F11%2F13%2FCF_443_E%2F</url>
<content type="text"><![CDATA[题目传送门443的D的思路非常的新奇呀,将数的大小关系用二进制位表示了出来题意:给你一个长度为$n$的序列$a$和$q$次询问,每次询问一个区间$[l,r]$,将这个区间提出来,执行以下操作:对于相邻两个数字$x,y$,删除$y$并将$x$替换为$x+2y$,问最后剩下的那个数最大为多少,答案模$1e9+7$分析: $ans = \sum_{i=0}^{m}a_{l+i}2^{k_{i}}$,除了$k_{0}=0$,这个$k$序列是由一些从$1$开始的连续自然数串组成的,例如$1,2,3 \dots 1,2 \dots$,如果我们能找出这些$1$的位置,那么答案就很好求了.我们通过枚举后缀来求$1$的位置,考虑一段区间,如果$\sum_{i=l}^{r}a_{i}2^{l - i}$大于$2e9$,那么不管前面的数是什么,该值都会变大,它的$1$的位置应该为$0$,若这个和小于$0$,那么$1$的位置就是$l-1$.对于一段长度为$m$区间,$1$的个数最多为$m$个,所以我们需要使用倍增来维护向前跳了$2^{k}$个$1$之后的位置.感觉自己都不知道自己在讲些什么1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;int add(int x,int y) { x += y; if(x >= mod) x -= mod; return x;}int mul(int x,int y) { LL z = 1LL * x * y; return z - z / mod * mod;}int a[maxn],s[maxn],p[maxn],inv[maxn];int f[maxn][20],d[maxn][20];int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,q,i,j,l,r; scanf("%d%d",&n,&q); for(i = p[0] = inv[0] = 1;i <= n; i++) { scanf("%d",&a[i]); inv[i] = mul(inv[i - 1],500000004); p[i] = mul(p[i - 1],2); s[i] = add(s[i - 1],mul(mod + a[i],p[i])); } for(i = 1;i <= n; i++) { LL x = 0; for(j = i;j > 0; j--) { x = (x * 2 + a[j]); if(x <= 0) { f[i][0] = j - 1; d[i][0] = add(0,mod + x * 2 % mod); break; } if(x > 2000000000) { f[i][0] = -1; break; } } } for(j = 1;j < 18; j++) { for(i = 1;i <= n; i++) { if(f[i][j - 1] == -1) f[i][j] = -1; else { f[i][j] = f[f[i][j - 1]][j - 1]; d[i][j] = add(d[i][j - 1],d[f[i][j - 1]][j - 1]); } } } while(q--) { scanf("%d%d",&l,&r); int ans = 0; for(i = 17;i >= 0; i--) { if(f[r][i] > l) { ans = add(ans,d[r][i]); r = f[r][i]; } } if(r >= l) ans = add(ans,mul(add(s[r],mod - s[l - 1]),inv[l])); printf("%d\n",ans); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#445(Div. 1)_E]]></title>
<url>%2F2017%2F11%2F11%2FCF_445_E%2F</url>
<content type="text"><![CDATA[题目传送门比赛打到一半CF炸了,感觉非常的累……题意:给你序列$a_{i}$,定义$f(x,n)=x \% a_{n},f(x,i)=x \% a_{i} + f(x \% a_{i},i + 1)$,求函数$f(x,1)$的最大值.分析:$f(x,1)=x \% a_{1} + x \% a_{1} \% a_{2} + \dots + x \% a_{1} \% a_{2} \dots \% a_{n}$,定义$b_{x,i} = x \% a_{1} \% a_{2} \dots \% a_{i}$.定理: 如果$f(m,1)$是最大值,那么一定存在至少一个$i$使得$b_{m,i} = a_{i} - 1$.证明:反证法,如果$f(m,1)$是最大值且不满足上述条件,那么对于$f(m + 1,1)$,我们可以得到$b_{m+1,i} = b_{m,i} + 1$,那么$f(m,1)$就肯定不是最大值,得证.做法: 用$map$维护一个$pair(c,w)$表示当$0 \leq b_{x,i} \leq c$时,前$i$个数的比$c$多的部分的和的最大值.当$a_{i} > c$时$w$不变;当$a_{i} \leq c$时区间由$[0,c]$变成$[0,a_{i}-1],[0,c \% a_{i}]$.答案就是$max(w + c * n)$ 123456789101112131415161718192021222324252627282930313233343536373839//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<LL,LL> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;map<LL,LL> q;vector<P> f;int main(){#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,i; LL x,p; scanf("%d",&n); scanf("%lld",&p); q[p - 1] = 0; for(i = 1;i < n; i++) { scanf("%lld",&x); if(x >= p) continue; f.clear(); auto e = q.lower_bound(x); for(auto u = e;u != q.end(); u++) f.push_back(*u); q.erase(e,q.end()); for(auto u:f) { q[x - 1] = max(q[x - 1],(u.first - x + 1) / x * x * i + u.second); q[u.first % x] = max(q[u.first % x],u.first / x * x * i + u.second); } } x = 0; for(auto e:q) x = max(x,e.first * n + e.second); printf("%lld\n",x); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[博= =客]]></title>
<url>%2F2017%2F11%2F09%2Fthe-second-article%2F</url>
<content type="text"><![CDATA[11.09给博客瞎搞了一个评论功能弄了上去……虽然好像兼容性不是特别的好,就这样吧(反正也觉得没人会评论的)搜索功能似乎至少要输入两个字才行……感觉非常的捉急 11.13那个友言似乎登不上去呀……默默的换成畅言试一下]]></content>
</entry>
<entry>
<title><![CDATA[青花引]]></title>
<url>%2F2017%2F11%2F02%2Fsong-qinghuayin%2F</url>
<content type="text"><![CDATA[一壶青花清水细撩蒹葭淋漓飒沓世外尽喧哗烟景细尘吹过咿咿呀呀琉璃灯下私语话一点朱砂春来秋去韶华古道遥遥牡丹亭外花风醇柔火千古灼烧不肯罢纹上锦鲤戏软纱慷慨够几话座上天下此番辗转天涯伏笔够几话一笔江枫一笔山隐结发眼过几冬夏 灰烬归家也再无双生花昌南夜雨凉透瓶身骨中化便装下茶的清雅酒的潇洒唐诗宋词浓墨重彩遥遥等春发只劝岁月少几寸浮夸当流光遇流萤染了白月牙宫商广寒鸦一身飒飒无瑕唇齿猎眉峰仕女簪花自逐岸上白马别了烂漫飞花萍踪浪迹谁人踏高山流水未达忽如远行才知江山如画尽归旁人羡煞而相思喑哑如她清平调起偏逢簌簌雪花不问千秋风流真或假春来花发袖中点点新芽浓淡跃然灯火又万家眠我情话鸾凤和鸣碎烟霞更长漏永雁平沙慷慨够几话座上天下此番辗转天涯伏笔够几话一笔江枫一笔山隐结发眼过几冬夏灰烬归家也再无双生花昌南夜雨凉透瓶身骨中化便装下茶的清雅酒的潇洒唐诗宋词浓墨重彩遥遥等春发只劝岁月少几寸浮夸当流光遇流萤染了白月牙宫商广寒鸦一身飒飒无瑕唇齿猎眉峰仕女簪花自逐岸上白马别了烂漫飞花昌南夜雨凉透瓶身骨中化便装下茶的清雅酒的潇洒唐诗宋词浓墨重彩遥遥等春发只劝岁月少几寸浮夸当流光遇流萤染了白月牙宫商广寒鸦一身飒飒无瑕唇齿猎眉峰仕女簪花自逐岸上白马别了烂漫飞花炉火白釉 青瓷花 水墨青花徐志摩轻吟一句情话,执笔一副情画。绽放一地情花,覆盖一片青瓦。共饮一杯清茶,同研一碗青砂。挽起一面轻纱,看清天边月牙。爱像水墨青花,何惧刹那芳华。]]></content>
</entry>
<entry>
<title><![CDATA[葬仙]]></title>
<url>%2F2017%2F10%2F02%2Fsong-zangxian%2F</url>
<content type="text"><![CDATA[倾覆八荒血染剑上一寸霜被万灵膜拜白衣世无双鬼面似笑又好似心伤这是宿命在逼迫我反抗永生执念寻觅相似花绽放那少年惊艳岁月争星芒仙路迢迢 枯骨路成王这是英雄他生来的战场 我曾背负世人谎血衣大杀过四方我曾望着星光伴一人而唱 我曾只手遮天光游走宇宙过洪荒我曾祈求天地与万物 护你佑你无恙 你可无恙? 永生执念寻觅相似花绽放那少年惊艳岁月争星芒仙路迢迢 枯骨路成王这是英雄他生来的战场我曾背负世人谎血衣大杀过四方我曾望着星光伴一人流浪我曾只手遮天光游走宇宙过洪荒我曾傲然天地与万物念你无恙 我曾背负世人妄暮色疲惫过丘芒我曾揽月摘星将一人殡葬 我曾覆手镇魍魉改写生死逆苍穹我曾震慑千古却只为重回昆仑山上 将故人葬]]></content>
</entry>
<entry>
<title><![CDATA[佩尔方程]]></title>
<url>%2F2017%2F10%2F02%2FPell%2F</url>
<content type="text"><![CDATA[连分数$\omega = a_{0} + \frac{1}{a_{1} + \frac{1}{a_{2} + \cdots }}$一个实数 $\omega$ 可以用一个正整数数列$\left[a_{i} \right]$表示,这样的表示方法称为连分数表示.有理数的连分数序列有限,无理数的连分数序列无限.给定$\left[a_{i} \right]$数列,求原数$\frac{p_{n}}{q_{n}}$的递推公式:$p_{n} = a_{n}p_{n-1}+p_{n-2},p_{-1}=1,p_{-2}=0$$q_{n} = a_{n}q_{n-1}+q_{n-2},q_{-1}=0,q_{-2}=1$一个实数的序列长度为$n$连分数表示亦称为一个数的$n$渐近分数. 佩尔(Pell)方程$x^{2}-Ny^{2}=1$佩尔方程有解的充要条件是正整数$N$不是完全平方数定理:若$\sqrt N$的渐近分数为$\frac{p_{k}}{q_{k}}$,则存在$n>0$,使得$p_{n}^{2}-Nq_{n}^{2}=1$递推寻找最小解:初始化:$p_{-1}=1,p_{-2}=0$$q_{-1}=0,q_{-2}=1$$a_{0}=\left \lfloor \sqrt{N} \right \rfloor$$g_{-1}=0,h_{-1}=1$递推寻找:$g_{i}=-g_{i-1}+a_{i}h_{i-1}$$h_{i}=\frac{N-g_{i}^{2}}{h_{i-1}}$$a_{i+1}=\left \lfloor \frac{g_{i}+a_{0}}{h_{i}} \right \rfloor$$p_{i}=a_{i}p_{i-1}+p_{i-2}$$q_{i}=a_{i}q_{i-1}+q_{i-2}$然后check $p_{i},q_{i}$ 如果求得了最小解$x_{1},y_{1}$,那么可以递推出第$k$大解:$x_{k}=x_{k-1}x_{1}+Ny_{k-1}y_{1}$$y_{k}=x_{k-1}y_{1}+y_{k-1}x_{1}$并且第$k$大解$(x_{k},y_{k})$满足$x_{k}+\sqrt{N}y_{k}=(x_{1}+\sqrt{N}y_{1})^{k}$所以当$k$比较大时,可以使用二元域的快速幂求解 第二类佩尔方程$x^{2}-Ny^{2}=-1$若上式有解,设其最小解为$(x_{0},y_{0})$,那么上式的所有解$(x_{k},y_{k})$满足$x_{k}+y_{k}\sqrt{N}=(x_{0}+y_{0}\sqrt{N})^{2k+1}$设$x^{2}-Ny^{2}=1$的最小解为$(a,b)$,满足$a+b\sqrt{N}=(x_{0}+y_{0}\sqrt{N})^{2}$]]></content>
</entry>
<entry>
<title><![CDATA[2017北京网络赛补]]></title>
<url>%2F2017%2F10%2F02%2FBeijing2017%2F</url>
<content type="text"><![CDATA[D.Agent Communication题意:给你一棵树,你需要加一条边,使得所有点对的距离的最大值最小.分析:加的边一定在直径上,先处理出所有点到直径的距离,然后仿照hdu5699即可123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1005;vector<int> g[maxn],f;int d[maxn],w[maxn];bool inl[maxn];int dfs(int u,int fa) { int x,k = u; for(auto v:g[u]) { if(v == fa || inl[v]) continue; d[v] = d[u] + 1; x = dfs(v,u); if(d[x] > d[k]) k = x; } return k;}bool dfs(int u,int fa,int w) { f.push_back(u); inl[u] = 1; if(u == w) return true; for(auto v:g[u]) { if(v == fa) continue; if(dfs(v,u,w)) return true; } f.pop_back(); inl[u] = 0; return false;}bool check(int k,int m) { int i,j,u,l1,l2,r1,r2; l1 = l2 = -mod; r1 = r2 = mod; for(i = 0;i < m; i++) { for(j = i + 1;j < m; j++) { if(j - i + w[i] +w[j] <= k) continue; u = k - 1 - w[i] - w[j]; l1 = max(l1,i + j - u); l2 = max(l2,j - i - u); r1 = min(r1,i + j + u); r2 = min(r2,j - i + u); } } if(l1 <= r1 && l2 <= r2) { if(l1 == r1 && l2 == r2) { if((l1 + l2) & 1) return false; else return true; } else return true; } else return false;}void solve() { int n,m,u,v,i,l,r,mid; scanf("%d",&n); for(i = 1;i <= n; i++) g[i].clear(); memset(inl,0,sizeof(inl)); for(i = 1;i < n; i++) { scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } d[1] = 1; u = dfs(1,0); d[u] = 1; v = dfs(u,0); f.clear(); dfs(u,0,v); m = f.size(); for(i = 0;i < m; i++) { d[f[i]] = 0; w[i] = d[dfs(f[i],0)]; } l = 0; r = 1005; while(l < r) { mid = (l + r) >> 1; if(check(mid,m)) r = mid; else l = mid + 1; } printf("%d\n",r);}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; scanf("%d",&t); while(t--) solve(); return 0;} F.Cake题意:有三个人在做$n$个蛋糕,每个蛋糕分三步,每人负责一步,只能做完上一步才能做下一步.每个人做的顺序必须一致,问最小总时间.分析:对于两个蛋糕A和B,定义$A < B$,当且仅当AB相邻时AB比BA要优。然后排序完跑一遍就行了12345678910111213141516171819202122232425262728293031323334353637383940414243//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;struct node { int a,b,c;} f[maxn];bool cmp(const node &x,const node &y) { int u = max(x.a + x.b,x.a + y.a); u = max(u + y.b,x.a + x.b + x.c) + y.c; int v = max(y.a + y.b,y.a + x.a); v = max(v + x.b,y.a + y.b + y.c) + x.c; return u < v;}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int n,i; LL da,db,dc; while(~scanf("%d",&n) && n) { for(i = 0;i < n; i++) scanf("%d%d%d",&f[i].a,&f[i].b,&f[i].c); sort(f,f + n,cmp); da = db = dc = 0; for(i = 0;i < n; i++) { da += f[i].a; db = max(db,da); db += f[i].b; dc = max(dc,db); dc += f[i].c; } printf("%lld\n",dc); } return 0;} H.Polynomial Product题意:给你两个多项式,定义卷积后的系数$c_{i}= max(a_{j}+b_{i-j})$,问哪些系数大于了$w$分析:排序之后,可以线性处理出对于$a_{i}$有哪些$b_{j}$会使得它们的和大于$w$,然后用$bitset$取一遍或,即可.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970//created by missever#include<bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int,int> P;const int mod = 1e9 + 7;const int maxn = 1e5 + 5;vector<P> fa,fb;bitset<1005> v1,ans1;bitset<maxn> v2,ans2;void solve(int t) { int n,m,w,x,i,j; scanf("%d%d%d",&n,&m,&w); fa.clear(); fb.clear(); for(i = 0; i < n; i++) { scanf("%d",&x); if(x == 0) continue; if(x == 1) x = 0; fa.push_back(P(x,i)); } for(i = 0; i < m; i++) { scanf("%d",&x); if(x == 0) continue; if(x == 1) x = 0; fb.push_back(P(x,i)); } x = n + m - 1; sort(fa.begin(),fa.end()); sort(fb.begin(),fb.end()); n = fa.size(); m = fb.size(); if(n > m) { swap(n,m); swap(fa,fb); } if(t < 4) { v2.reset(); ans2.reset(); for(i = 0,j = m - 1; i < n; i++) { while(j >= 0 && (LL)fb[j].first + fa[i].first > w) v2[fb[j--].second] = 1; ans2 |= v2 << fa[i].second; } for(i = 0; i < x; i++) putchar(ans2[i] ? 'Y' : 'N'); puts(""); } else { v1.reset(); ans1.reset(); for(i = 0,j = m - 1; i < n; i++) { while(j >= 0 && (LL)fb[j].first + fa[i].first > w) v1[fb[j--].second] = 1; ans1 |= v1 << fa[i].second; } for(i = 0; i < x; i++) putchar(ans1[i] ? 'Y' : 'N'); puts(""); }}int main() {#ifdef CX_TEST freopen("E:\\program--GG\\test_in.txt", "r", stdin);#endif int t; scanf("%d",&t); while(t--) solve(t); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[Dividing_Area]]></title>
<url>%2F2017%2F07%2F10%2Fgym-101237J%2F</url>
<content type="text"><![CDATA[题目传送门题意:给你$n$个点,有$Q$次操作,操作分别为在两个点之间连一条边和询问在一条边左边的相邻的封闭图形的面积。并且最后$n$个点会形成一个平面图。我们把操作离线,对最后的平面图进行转对偶图操作,把每条边拆成两条单向边,并且用并查集把有向边左边的空白区域和该边连接起来,树根为空白区域,并记录空白区域面积。然后倒着操作,如果是加边操作,则删除该边,并把两个有向边所相邻的空白区域用并查集合并,查询面积操作即访问树根即可。NOTE:极角排序写挫了、、RE20不能自拔……123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;typedef pair<int,int> P;typedef pair<double,int> PD;const int maxn = 1e6 + 5;const double eps = 1e-10;const double pi = acos(-1);inline int sgn(double x) { if(x < -eps) return -1; else if(x > eps) return 1; else return 0;}struct Point { int x,y; Point(int _x = 0,int _y = 0): x(_x),y(_y) {} Point operator + (const Point &b) const { return Point(x + b.x,y + b.y); } Point operator - (const Point &b) const { return Point(x - b.x,y - b.y); } LL operator * (const Point &b) const { return (1LL * x * b.x + 1LL * y * b.y); } LL operator ^ (const Point &b) const { return (1LL * x * b.y - 1LL * y * b.x); }};Point p[maxn];P f[maxn];struct que { int op,u,v; que(int _op = 0,int _u = 0,int _v = 0): op(_op),u(_u),v(_v) {}} q[maxn];int n,tot = 0;bool vis[maxn * 2];map<P,int> mp;vector<PD> g[maxn];int df[maxn * 4];map<int,LL> mpp;map<int,int> gg[maxn];LL sm = 0;int sk;LL ans[maxn];double get_ang(int u,int v) { return atan2(p[v].y - p[u].y,p[v].x - p[u].x);}int fff(int x) { if(df[x] != x) df[x] = fff(df[x]); return df[x];}void work(int u,PD e) { int v1 = u,v2 = e.second,k = 0; f[k++] = P(v1,v2); while(v2 != u) { v1 = gg[v2][v1]; if(v1 == 0) v1 = g[v2].back().second; else v1 = g[v2][v1 - 1].second; swap(v1,v2); f[k++] = P(v1,v2); } LL ss = 0; for(int i = 0; i < k; i++) ss += p[f[i].first] ^ p[f[i].second]; if(ss <= 0) mpp[tot] = -1; else mpp[tot] = ss; df[tot] = tot; for(int i = 0; i < k; i++) { int j = mp[f[i]]; vis[j] = 1; df[j] = tot; } tot++;}bool cmp(const PD &a,const PD &b){ if(sgn(b.first - a.first) == 0) return ((p[b.second] - p[sk]) ^ (p[a.second] - p[sk])) < 0; else return b.first - a.first > eps;}void build() { int i,j; for(i = 1; i <= n; i++){ sk = i; sort(g[i].begin(),g[i].end(),cmp); for(j = 0;j < g[i].size(); j++) gg[i][g[i][j].second] = j; } for(i = 1; i <= n; i++) { for(auto e:g[i]) { j = mp[P(i,e.second)]; if(vis[j]) continue; work(i,e); } }}int main() { int Q,i,op,u,v; scanf("%d",&n); for(i = 1; i <= n; i++) scanf("%d%d",&p[i].x,&p[i].y); scanf("%d",&Q); for(i = 1; i <= Q; i++) { scanf("%d%d%d",&op,&u,&v); u++; v++; q[i] = que(op,u,v); if(op == 1) { g[u].push_back(PD(get_ang(u,v),v)); g[v].push_back(PD(get_ang(v,u),u)); mp[P(u,v)] = tot++; mp[P(v,u)] = tot++; } } build(); int tt = 0; for(i = Q; i > 0; i--) { if(q[i].op == 1) { u = fff(mp[P(q[i].u,q[i].v)]); v = fff(mp[P(q[i].v,q[i].u)]); if(u == v) continue; if(mpp[u] == -1 || mpp[v] == -1) mpp[u] = -1; else mpp[u] += mpp[v]; df[v] = u; } else { u = fff(mp[P(q[i].u,q[i].v)]); ans[tt++] = mpp[u]; } } for(i = tt - 1; i >= 0; i--) printf("%lld\n",ans[i]); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#421(Div. 1)_D]]></title>
<url>%2F2017%2F07%2F05%2FCF-421_D%2F</url>
<content type="text"><![CDATA[题目传送门题意:外星球每隔T秒中只有一秒可以被观测到,其它T-1秒无法被观测。n个天文学家(分别编号为1,…,n)轮流观测天空1秒,且第i+1个科学家在第i个天文学家后ai+1秒后才执行观测,而第一个天文学家则在第n个天文学家后a1秒后才执行观测,且第一个天文学家在0秒时执行第一次观测(即第一个天文学家观测的时间是[0,1),第二个科学家在[a2,a2+1)时观测,而最后一个天文学家在[a2+a3+…+an-1,a2+a3+…+an-1+1)时观测,之后再过a1秒后第一个天文学家继续观测)。由于外星球具体在首次观测之后的T秒中的哪一秒出现是不确定的,若外星球在[i,i+1)时出现(0<=i<T-1),且天文学家j是首个观测到星球的人,则称j抢占了[i,i+1)时间片段。已知T,n,a1,….,an其中(1<=T<=1e9,1<=n<=1e5,1<=a1,…,an<=1e9)。输出每个天文学家所抢占的时间片段数。 解法:把n个科学家分成多个组,每组的人的观测的时间点集合在模T之后是相同的,那么他们就构成了一个环,我们只需要对每个组排序,然后就可以愉快的算出各个科学家的时间片段数了。如何确定这名科学家在哪一组和组内的排序依靠建立同余方程,并用裴蜀定理和扩展欧几里德求解。懒得写了具体实现不如看官方题解23312345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;typedef pair<int,int> P;const int maxn = 2e5 + 5;int a[maxn],tot,mm,ans[maxn];vector<P> g[maxn];unordered_map<int,int> mp;void extend_Euclid(int a, int b, int &x, int &y){ if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); int tmp = x; x = y; y = tmp - (a / b) * y;}int get_modans(int a,int m,int b){ if(a == 0) return 0; if(b == 0) return 0; int d = __gcd(a,m); int x,y; extend_Euclid(a / d,m / d,x,y); x = 1LL * x * b / d % m; x = (x % m + m) % m; x %= mm; return x;}bool cmp(const P &a,const P &b){ if(a.first == b.first) return a.second > b.second; else return a.first < b.first;}void solve(vector<P> &f){ int n = f.size(); sort(f.begin(),f.end(),cmp); f.push_back(P(mm + f[0].first,0)); for(int i = 0;i < n; i++) ans[f[i].second] = f[i + 1].first - f[i].first;}int main(){ int t,n,i; scanf("%d%d",&t,&n); scanf("%d",&a[n]); for(i = 1;i < n; i++) scanf("%d",&a[i]); for(i = 1;i <= n; i++){ a[i] %= t; a[i] += a[i - 1]; if(a[i] >= t) a[i] -= t; } int k = __gcd(a[n] + t,t); mm = t / k; for(i = 0;i < n; i++){ int x = a[i] % k; if(mp[x] == 0) mp[x] = ++tot; g[mp[x]].push_back(P(get_modans(a[n],t,(a[i] - x + t) % t),i)); } for(i = 1;i <= tot; i++) solve(g[i]); for(i = 0;i < n; i++) printf("%d ",ans[i]); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#415(Div. 1)_E]]></title>
<url>%2F2017%2F06%2F14%2FCF-415_E%2F</url>
<content type="text"><![CDATA[参考了一下大神的题解、、题解传送门:[https://blog.sengxian.com/solutions/cf-809e] 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;const int maxn = 2e5 + 5;int n,rt;vector<int> g[maxn],g2[maxn],fac[maxn],vec[maxn];int cnt = 0,bn = 0,b[maxn * 2],a[maxn];int f[maxn * 2],dfn[maxn],dis[maxn],st[maxn];bool flag[maxn];int phi[maxn],pri[maxn],mu[maxn],inv[maxn],cc[maxn],xc[maxn];int tot = 0;void add(int &x,int y) { x += y; while(x >= MAX) x -= MAX; while(x < 0) x += MAX;}int mod(int x,int y) { LL z = 1LL * x * y; return z - z / MAX * MAX;}void dfs(int u,int fa) { int tmp = ++cnt; b[++bn] = tmp; f[tmp] = u; dfn[u] = bn; for(auto v:fac[a[u]]) vec[v].push_back(u); for (auto v:g[u]) { if (v == fa) continue; dis[v] = dis[u] + 1; dfs(v,u); b[++bn] = tmp; }}int dp[maxn * 2][20];void rmq_init() { int i,j; for (i = 1; i <= bn; i++) dp[i][0] = b[i]; int m = floor(log(bn*1.0)/log(2.0)); for (j = 1; j <= m; j++) for (i=1; i <= bn-(1<<j)+1 ; i++) dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int rmq(int l,int r) { int k = floor(log((r-l+1)*1.0)/log(2.0)); return min(dp[l][k],dp[r-(1<<k)+1][k]);}int lca(int x,int y) { if(x == y) return x; if (dfn[x] > dfn[y]) swap(x,y); int k = rmq(dfn[x],dfn[y]); return f[k];}bool cmp(const int &i, const int &j) { return dfn[i] < dfn[j];}void build_tree(vector<int> &vc) { int sz = 0,k = vc.size(); sort(vc.begin(),vc.end(),cmp); st[sz] = 0; g2[0].clear(); for (int i = 0; i < k; ++i) { int u = vc[i], ll = lca(u, st[sz]); g2[u].clear(); if (ll == st[sz]) st[++sz] = u; else { while (sz >= 1 && dis[st[sz - 1]] >= dis[ll]) { g2[st[sz - 1]].push_back(st[sz]); sz--; } if (st[sz] != ll) { g2[ll].clear(); g2[ll].push_back(st[sz--]); st[++sz] = ll; } st[++sz] = u; } } for (int i = 0; i < sz; ++i) g2[st[i]].push_back(st[i + 1]);}int dfs2(int u,int ff){ int s1,s2; s1 = s2 = 0; xc[u] = (a[u] % ff == 0) ? phi[a[u]] : 0; for(auto v:g2[u]){ add(s1,dfs2(v,ff)); add(s2,mod(xc[u],xc[v])); add(xc[u],xc[v]); } add(s1,mod(s2,2 * dis[u])); if(a[u] % ff == 0) add(s1,mod(dis[u],mod(phi[a[u]],phi[a[u]]))); return s1;}void Get_phi() { mu[1] = phi[1] = 1; for(int i = 2; i <= n; i++) { if(!flag[i]) { pri[tot++] = i; phi[i] = i - 1; mu[i] = -1; } for(int j = 0; j < tot; j++) { if(i * pri[j] > n) break; flag[i * pri[j]] = true; if(i % pri[j] == 0) { mu[i * pri[j]] = 0; phi[i * pri[j]] = pri[j] * phi[i]; break; } else { phi[i * pri[j]] = (pri[j] - 1) * phi[i]; mu[i * pri[j]] = -mu[i]; } } }}int calc(int u) { int s1,s2; s1 = s2 = 0; for(auto v:vec[u]) { add(s1,phi[a[v]]); add(s2,mod(phi[a[v]],dis[v])); } s1 = mod(2,mod(s1,s2)); build_tree(vec[u]); add(s1,-2 * dfs2(0,u)); return s1;}void solve() { Get_phi(); for(int i = 1; i <= n; i++) { for(int j = i; j <= n; j += i) fac[j].push_back(i); } inv[1] = 1; for(int i = 2; i <= n; i++) add(inv[i],MAX - mod(MAX / i,inv[MAX % i])); dis[1] = 1; dfs(1,0); rmq_init(); for(int i = 1; i <= n; i++) cc[i] = calc(i); int ans = 0; for(int i = 1; i <= n; i++) { int s = 0; for(int j = 1; i * j <= n; j++) add(s,mu[j] * cc[i * j]); add(ans,mod(mod(s,i),inv[phi[i]])); } ans = mod(ans,mod(inv[n],inv[n - 1])); printf("%d\n",ans);}int main() { int i,u,v; scanf("%d",&n); for(i = 1; i <= n; i++) scanf("%d",&a[i]); for(i = 1; i < n; i++) { scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } solve(); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[URAL-1894-Non-Flying-Weather]]></title>
<url>%2F2017%2F06%2F14%2Fural1894%2F</url>
<content type="text"><![CDATA[题意:给你两个相交的凸包,其中一个可以任意移动,问最少多久能使两个凸包分离前置技能点:闽科夫斯基和:设P和Q是两个凸包,则有闽科夫斯基和 P+Q={a+b|a∈P,b∈Q} ,闽科夫斯基差 P-Q={a-b|a∈P,b∈Q}性质:P+Q是一个凸包,同时也是P和Q的所有并踵点对的和的集合,P+Q顶点数不超过P和Q的顶点和其差P-Q是一个凸包,同时也是P和Q的所有对踵点对的差的集合,P-Q顶点数不超过P和Q的顶点和,若P和Q相交,则P-Q包含原点那么,本题就是求一个闽科夫斯基差的凸包,找出原点到凸包的最短距离……所以可以用旋转卡壳跑出所有对踵点对,然后求一下点-边的对踵点对中点到直线的距离就好了 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;const double eps = 1e-10;const double pi = acos(-1);const int maxn = 5e4 + 5;inline int sgn(double x) { if(x < -eps) return -1; else if(x > eps) return 1; else return 0;}struct Point { double x,y; Point(double _x = 0.0,double _y = 0.0): x(_x),y(_y) {} Point operator + (const Point &b) const { return Point(x + b.x,y + b.y); } Point operator - (const Point &b) const { return Point(x - b.x,y - b.y); } double operator * (const Point &b) const { //点乘 return (x * b.x + y * b.y); } double operator ^ (const Point &b) const { //叉乘,判断b点的相对于该点位置关系 左正右负 return (x * b.y - y * b.x); } Point operator * (double b) { return Point(x * b,y * b); } double norm() { //求模 return sqrt(x * x + y * y); }};struct Line { Point s,e; Line() {} Line(Point _s,Point _e) { s = _s; e = _e; }};double dist(Point &a,Point &b) { return (a - b).norm();}Point Point_to_Line(Point p,Line l){ double t = ((p - l.s) * (l.e - l.s)) / ((l.e - l.s) * (l.e - l.s)); return Point(l.s.x + (l.e.x - l.s.x) * t,l.s.y + (l.e.y - l.s.y) * t);}//旋转卡壳double rot_solve(Point a[],Point b[],int n,int m) { int fa,fb,i; Point u; for(fa = i = 0; i < n; i++) { if(a[i].y < a[fa].y) fa = i; } for(fb = i = 0; i < m; i++) { if(b[i].y > b[fb].y) fb = i; } a[n] = a[0]; b[m] = b[0]; double ans = 1e18; for(i = 0; i < n; i++) { while(sgn(((a[fa + 1] - a[fa]) ^ (b[fb + 1] - a[fa]))- ((a[fa + 1] - a[fa]) ^ (b[fb] - a[fa]))) == 1) fb = (fb + 1) % m; u = Point_to_Line(b[fb],Line(a[fa],a[fa + 1])); ans = min(ans,(b[fb] - u).norm()); fa = (fa + 1) % n; } return ans;}Point a[maxn],b[maxn];int main() { int n,m,i; double x,y; scanf("%d%d",&n,&m); for(i = 0; i < n; i++) { scanf("%lf%lf",&x,&y); a[i] = Point(x,y); } for(i = 0; i < m; i++) { scanf("%lf%lf",&x,&y); b[i] = Point(x,y); } double ans = min(rot_solve(a,b,n,m),rot_solve(b,a,m,n)); ans -= 60.0; if(sgn(ans) <= 0) printf("0\n"); else printf("%.12f\n",ans); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[CF_#418(Div. 2)_E]]></title>
<url>%2F2017%2F06%2F08%2FCF-418(Div.%202)_E%2F</url>
<content type="text"><![CDATA[我们按到点1的最短路径长度分层,因为满足$l_{i} \leq l_{i + 1}$,那么每一层的数一定是连续的。因为最短路径唯一,所以除1外的每个点都有且仅有一条边指向上一层,其它边要么指向同一层其它点,要么指向下一层。然后我们可以构造$DP$状态$f[i][j][k][l]$表示处理到第$i$个点,上一层有$j$条边尚未连接,这一层有$k$个点还有1条边位连接和有$l$个点还有2条边未连接。转移即可。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;const int inv2 = 500000004;int f[55][55][55][55];int d[55],inv[55];void add(int &x,int y) { x += y; if(x >= MAX) x -= MAX;}int mul(int x,int y) { LL z = 1LL * x * y; return z - z / MAX * MAX;}int main() { int n,i,j,k,l; scanf("%d",&n); for(i = 1; i <= n; i++) scanf("%d",&d[i]); inv[0] = 1; for(i = 1; i <= n; i++) inv[i] = mul(inv[i - 1],inv2); if(d[1] == 2) f[2][d[1]][0][0] = inv2; else f[2][d[1]][0][0] = mul(333333336,inv2); for(i = 2; i <= n; i++) { for(j = 0; j < i; j++) { for(k = 0; k + j < i; k++) { if(f[i][0][j][k]) add(f[i][j + k * 2][0][0],mul(f[i][0][j][k],inv[k])); } } for(j = 1; j <= n - i + 1; j++) { for(k = 0; k < i; k++) { for(l = 0; l + k < i; l++) { if(f[i][j][k][l]) { int x = mul(f[i][j][k][l],j); if(d[i] == 2) { add(f[i + 1][j - 1][k + 1][l],x); if(k) add(f[i + 1][j - 1][k - 1][l],mul(x,k)); if(l) add(f[i + 1][j - 1][k + 1][l - 1],mul(x,l)); } else { add(f[i + 1][j - 1][k][l + 1],x); add(f[i + 1][j - 1][k][l],mul(x,k)); if(l) add(f[i + 1][j - 1][k + 2][l - 1],mul(x,l)); if(k >= 2) add(f[i + 1][j - 1][k - 2][l],mul(mul(x,inv2),mul(k,k - 1))); if(l >= 2) add(f[i + 1][j - 1][k + 2][l - 2],mul(mul(x,inv2),mul(l,l - 1))); if(k && l) add(f[i + 1][j - 1][k][l - 1],mul(x,mul(k,l))); } } } } } } printf("%d\n",f[n + 1][0][0][0]); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[ZOJ2112]]></title>
<url>%2F2017%2F06%2F05%2Fzoj2112%2F</url>
<content type="text"><![CDATA[这道题就是带修改的求区间第k大非常经典的整体二分的题,因为满足查询的答案具有二分性,修改对答案的贡献相互独立,且可离线具体过程就是通过二分总体的答案,把最后答案小于mid的询问和值小于mid操作扔进一组,把其它的扔进另一组,使总体复杂度为$nlog^{2}n$ 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;const int maxn = 1e5 + 5;struct node { int x,y,tp,id,k; node(int _x = 0,int _y = 0,int r = 0,int z = 0,int d = 0): x(_x),y(_y),tp(r),id(z),k(d) {};} f[maxn],q1[maxn],q2[maxn];int tot,num,n;int ans[maxn],a[maxn],g[maxn];int lowbit(int x) { return x & (-x);}void add(int x,int d) { while(x <= n) { g[x] += d; x += lowbit(x); }}int ff(int x) { int s = 0; while(x > 0) { s += g[x]; x -= lowbit(x); } return s;}void solve(int ql,int qr,int l,int r) { if(ql > qr) return; if(l == r) { for(int i = ql; i <= qr; i++) { if(f[i].tp == 3) ans[f[i].id] = l; } return; } int mid = (l + r) >> 1; int t1 = 0,t2 = 0; for(int i = ql; i <= qr; i++) { if(f[i].tp == 1) { if(f[i].x <= mid) { add(f[i].id,1); q1[t1++] = f[i]; } else q2[t2++] = f[i]; } else if(f[i].tp == 2) { if(f[i].x <= mid) { add(f[i].id,-1); q1[t1++] = f[i]; } else q2[t2++] = f[i]; } else { int m = ff(f[i].y) - ff(f[i].x - 1); if(m >= f[i].k) q1[t1++] = f[i]; else { f[i].k -= m; q2[t2++] = f[i]; } } } for(int i = ql; i <= qr; i++) { if(f[i].tp == 1) { if(f[i].x <= mid) add(f[i].id,-1); } else if(f[i].tp == 2) { if(f[i].x <= mid) add(f[i].id,1); } } memcpy(f + ql, q1, t1 * sizeof(node)); memcpy(f + ql + t1, q2, t2 * sizeof(node)); solve(ql,ql + t1 - 1,l,mid); solve(ql + t1,qr,mid + 1,r);}int main() { int t,m,i,x,l,r; char e; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); tot = num = 0; for(i = 1; i <= n; i++) { scanf("%d",&a[i]); f[++tot] = node(a[i],0,1,i,0); } for(i = 0; i < m; i++) { scanf(" %c",&e); //cout<<i<<endl; if(e == 'Q') { scanf("%d%d%d",&l,&r,&x); f[++tot] = node(l,r,3,++num,x); } else { scanf("%d%d",&l,&x); f[++tot] = node(a[l],0,2,l,0); f[++tot] = node(x,0,1,l,0); a[l] = x; } } //cout<<"----"<<endl; solve(1,tot,1,1000000000); for(i = 1; i <= num; i++) printf("%d\n",ans[i]); } return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[敲黑板~]]></title>
<url>%2F2017%2F06%2F04%2Fplan2%2F</url>
<content type="text"><![CDATA[需要疯狂刷题了……然后写题解、、]]></content>
</entry>
<entry>
<title><![CDATA[ACM知识点]]></title>
<url>%2F2017%2F03%2F15%2Fplan%2F</url>
<content type="text"><![CDATA[啦啦啦~~2017.06.15更新 [ ] 基础算法 [x] 模拟 [x] 枚举 [x] 贪心 [x] 高精度 [x] 排序 [x] 递推 [x] 递归 [x] 二分 [ ] 01分数规划 [ ] 整体二分 [x] 倍增 [x] 位运算 [x] 离散化 [ ] 分块 [x] 前缀和 [x] 启发式合并 [x] 分治 [ ] 随机化 [x] 莫队算法 [ ] 数据结构 [x] 队列 [x] 栈 [x] 堆 [x] 链表 [x] 哈希表 [x] 树状数组 [x] 线段树 [ ] 平衡树 [ ] Spaly [ ] Treap [ ] SBT [x] 主席树 [ ] KD树 [ ] 树套树 [x] STL [ ] 图论(有待重新学习) [ ] 搜索 [x] DFS [x] BFS [x] 记忆化 [ ] A* [ ] IDA* [ ] 模拟退火 [ ] 爬山算法 [ ] 蚁群算法? [x] 并查集 [x] 欧拉图 [x] 拓扑排序 [ ] 最短路 [x] SPFA [x] Dijkstra [x] Floyd [ ] k短路 [x] 差分约束 [x] Tarjan [x] 强连通 [x] 双连通 [x] LCA [x] 2-SAT [ ] 二分图 [ ] 最大匹配 [ ] 最大权匹配 [ ] 网络流 [ ] 最大流最小割 [ ] 费用流 [ ] 有界流 [ ] 树 [x] 最小生成树 [x] DFS序 [x] 重心 [x] 直径 [x] LCA [x] 树分治 [ ] 树同构 [ ] 树链剖分 [ ] LCT [ ] 基环树 [ ] 带花树(非二分图最大匹配) [x] 最小树形图 [ ] 字符串 [x] KMP [x] 最小表示法 [x] AC自动机 [x] Trie树 [x] 后缀数组 [x] 后缀自动机 [x] Manacher [x] 回文自动机 [ ] DP [x] 背包 [x] 区间DP [x] 树形DP [x] 数位DP [x] 期望DP [x] 记忆化搜索DP [x] 状压DP [ ] 轮廓线DP [x] 四边形不等式优化 [x] 斜率优化 [ ] 几何 [x] 叉积和点积 [x] 凸包 [x] 旋转卡壳 [x] 半平面交 [x] Pick定理 [x] 辛普森积分 [x] 三角剖分 [ ] 随机增量 [ ] 反演变换 [ ] 数学 [ ] 博弈 [x] SG函数 [ ] A-Beta剪枝 [ ] 极大极小搜索 [x] 线性筛 [x] 素数测试 [x] 欧拉函数 [x] 快速幂 [x] GCD [x] EXGCD [x] 乘法逆元 [x] CRT [x] 容斥 [x] 矩阵 [x] Poyla定理 [x] 组合数 [ ] BSGS [ ] 单纯形 [x] 拉格朗日插值法 [x] FFT & NTT [x] 多项式求逆&开方 [x] 反演]]></content>
</entry>
<entry>
<title><![CDATA[miss and miss]]></title>
<url>%2F2017%2F03%2F15%2Fyou%2F</url>
<content type="text"><![CDATA[和有爱的人在一起,每一段恋情,都能成全一个更好的彼此 风信子的风 春日游,杏花吹满头。陌上谁家年少足风流?总有一个人,总有一个时刻,会让你望她的着聊天窗口发呆半天,反反复复写下了一句又一句想说的话,最后又一个字一个字的删掉……即使写下了,手指也会停留在发送键上久久不敢按下……那是一道比做高考语文题还需要反复琢磨的题……]]></content>
</entry>
<entry>
<title><![CDATA[maybe]]></title>
<url>%2F2017%2F03%2F04%2Fmiss%2F</url>
<content type="text"><![CDATA[和有爱的人在一起,每一段恋情,都能成全一个更好的彼此有些东西,放下了,对大家都好 我们都要含蓄一点~ 002582是好想你今晚月色真美是我爱你ρ=a(1+cosθ)是心形线下图是I LOVE U的函数表达式 不恨此花飞尽,恨西园,落红难缀、去年今日此门中,人面桃花相映红。人面不知何处在,桃花依旧笑春风。 山有木兮木有枝,心悦君兮君不知愿岁月可回首,且以深情共白头谁拿流年乱了浮生,又借浮生乱了红尘。此生若能得幸福安稳,谁又愿颠沛流离 心若没有栖息的地方,到哪里都是流浪]]></content>
</entry>
<entry>
<title><![CDATA[CF_#388(Div. 2)_E]]></title>
<url>%2F2016%2F12%2F20%2FCF-388(Div.%202)_E%2F</url>
<content type="text"><![CDATA[题目传送门题意略、首先,我们可以发现,每对数对答案的贡献是独立的,于是,我们先考虑第$i$个数和第$j$个数对答案的贡献$P\left ( i,j \right )$(下标从$1$开始):可以,算出,包含$i$和$j$的区间个数为$i\left ( n - j + 1 \right )$个,对于每个区间,我们可以发现第$i$个数在第$j$个数前面的概率和第$i$个数在第$j$个数后面的概率是相同的,都是$\frac{1}{2}$(原因想想就知道了)。当选择的区间没有同时包含$i$和$j$时,其贡献为$\left[ a_i > a_j \right]$所以,我们就能得到$P\left ( i,j \right )= \left ( 1 - \frac{2i\left ( n - j + 1 \right )}{n\left ( n + 1 \right )}\right )\left [ a_{i}> a_{j} \right ] + \frac{i\left ( n - j + 1 \right )}{n\left ( n + 1 \right )}$所以,最后的答案就是$$\sum_{i = 1}^{n -1}\sum_{j = i + 1}^{n}\left ( 1 - \frac{2i\left ( n - j + 1 \right )}{n\left ( n + 1 \right )}\right )\left [ a_{i}> a_{j} \right ] + \frac{i\left ( n - j + 1 \right )}{n\left ( n + 1 \right )}$$当然,我们肯定不能暴力枚举每一对$i$和$j$,但是,我们把上式变形一下,然后化简,就可以得到$$\sum_{i = 1}^{n - 1}\left ( \frac{i\left ( n - i \right )\left ( n - i + 1 \right )}{2n\left ( n + 1 \right )} + \sum_{j = i + 1}^{n}\left [ a_{i} > a_{j} \right ] + \frac{2i}{n\left ( n + 1 \right )} \sum_{j = i + 1}^{n}\left ( n - j + 1 \right )\left [ a_{i}> a_{j} \right ] \right )$$右边的两个和式一个就是求逆序数个数,另一个就是求逆序数的下标和,显然都可以在$nlogn$的时间维护出来所以……就做出来啦 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;typedef pair<LL,LL> P;const int maxn = 100005;LL sum[maxn * 4];int num[maxn * 4];int a[maxn],n;void add(int t,int l,int r,int x){ if(l == r) { num[t]++; sum[t] += n - x + 1; return; } int mid = (l + r) >> 1; if(a[x] <= mid) add(t<<1,l,mid,x); else add(t<<1|1,mid + 1,r,x); num[t]++; sum[t] += n - x + 1;}P query(int t,int l,int r,int x){ if(r <= a[x]) return P(sum[t],num[t]); int mid = (l + r) >> 1; if(a[x] <= mid) return query(t<<1,l,mid,x); else { P u,v; u = query(t<<1,l,mid,x); v = query(t<<1|1,mid + 1,r,x); return P(u.first + v.first,u.second + v.second); }}int main(){ int i; P u; LL f = 0,e = 0; long double ans; scanf("%d",&n); for(i = 1;i <= n; i++) scanf("%d",&a[i]); add(1,1,n,n); for(i = n - 1;i > 0; i--) { e += 1LL * (n - i) * (n - i + 1) / 2 * i; u = query(1,1,n,i); e -= u.first * i * 2LL; f += u.second; add(1,1,n,i); } ans = 1.0 * e / (1LL * n * (n + 1)) + f; printf("%.10f\n",(double)ans); return 0;} 后记:使用下标要加斜杠,不然显示不出来大括号……也有问题,还是别用了结论:GFM并不是标准的markdown]]></content>
</entry>
<entry>
<title><![CDATA[CF_#384(Div. 2)_E]]></title>
<url>%2F2016%2F12%2F15%2FCF-384(Div.%202)_E%2F</url>
<content type="text"><![CDATA[题目传送门题意就是给你一个只含数字1~8的序列,让你找到一个最长的子序列,这个子序列满足1~8的个数相差不超过1,相同数字必须连续出现。首先,我们假设选择的同一数字最少个数为t,那么最多个数就为t+1,然后我们可以枚举这个t是多少,或者二分这个t。然后我们考虑对于一个给定的t,怎么求答案,我们考虑用一个数组f[i][j]表示计算了前i个数状态为j的最大个数,j表示1~8中哪些数字已经选了,因为题目要求相同数字必须连续,所以每种数字只用选一次,所以可以用DP很好的实现。然后我们考虑转移,定义b[k]表示第k个数字从i+1开始的第t次出现的最小位置,b[k]表示第k个数字从i+1开始的第t+1次出现的最小位置,然后就有转移方程12updata(f[b[k]][j | (1 << k)],f[i][j] + t);updata(f[c[k]][j | (1 << k)],f[i][j] + t + 1); 而b[k]和c[k]我们可以在线性时间贪心出来,具体实现看代码、1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;int a[1205],n,ans = 0;int f[1205][1<<8],b[9],c[9];void updata(int &x,int y){ if(x == -1) x = y; else x = max(x,y);}bool check(int t){ memset(f,-1,sizeof(f)); int i,j,k; for(i = 0; i < 8; i++) { j = 0; b[i] = 0; while(j < t && b[i] <= n) { b[i]++; if(a[b[i]] == i) j++; } c[i] = b[i]; while(j <= t && c[i] <= n) { c[i]++; if(a[c[i]] == i) j++; } } for(k = 0; k < 8; k++) { updata(f[b[k]][(1 << k)],t); updata(f[c[k]][(1 << k)],t + 1); } for(i = 1; i <= n; i++) { j = a[i]; b[j] = c[j]; c[j]++; while(a[c[j]] != j && c[j] <= n) c[j]++; for(j = 0; j < (1 << 8); j++) { if(f[i][j] != -1) { for(k = 0; k < 8; k++) { if(!(j & (1 << k))) { updata(f[b[k]][j | (1 << k)],f[i][j] + t); updata(f[c[k]][j | (1 << k)],f[i][j] + t + 1); } } } } } i = -1; for(j = 1; j <= n; j++) i = max(i,f[j][(1 << 8) - 1]); ans = max(ans,i); return (i >= 0);}int main(){ int i,l,r,mid; int p[10]; memset(p,0,sizeof(p)); scanf("%d",&n); for(i = 1; i <= n; i++) { scanf("%d",&a[i]); a[i]--; p[a[i]] = 1; } for(i = 0; i < 8; i++) ans += p[i]; l = 1; r = n / 8; while(l <= r) { mid = (l + r) >> 1; if(check(mid)) l = mid + 1; else r = mid - 1; } printf("%d\n",ans); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[无题]]></title>
<url>%2F2016%2F12%2F10%2Fluanluande%2F</url>
<content type="text"><![CDATA[心似繁星,情如春水每天的脑子都是那么的乱,那么,我为什么不把那些碎片化的思绪串接一下呢、 思时间呀时间,你去哪里了呀……虽然才大二,但是感觉实习已经离我不远了……所有害怕面对的,终会去面对,所有不想结束的,终会去结束、 弃比赛雪崩,考试忘记……好想好想去睡那么一觉……感觉需要颓废一天了……]]></content>
</entry>
<entry>
<title><![CDATA[临行、前夕]]></title>
<url>%2F2016%2F12%2F08%2Fwho_know%2F</url>
<content type="text"><![CDATA[明天就要去上海参加EC-final了,但是此文与此无关,迷迷迷 昨日,未识 成都的天气,在经历了几天的雾霾,现在似乎有了一些些好转。不过温度,似乎越来越冷了呢。 不知几时,地上的银杏落叶已经堆满,冬初的凄凉,在那泛黄的世界中被尽数诉说。行走在其间,总有着一种时间的沧桑感。对呀,已经又是一年了,这一学期也快要结束了。时间过得总是那么的快,感觉我都来不及驻足观望一番,就都过去了,只能去匆匆迎接新的时光。 听闻以前的我很高冷,其实仔细想想,现在的我,似乎真的与以前不同了呢。是自我保护意识太强了吗,或是无话可说,或是其它什么的,以前的我话似乎比现在少很多。虽然,我也不认为我现在话就很多了。应该,对熟一点人,我的话才会多那么一些吧。不过,有时候想想,我为什么一定要话多呢,我只需要做那个我自己认为可以的我就好了。酒逢知己千杯少,话不投机半句多 有时候,也会想让自己作出改变,于是有时候就会决定自己要把这个改掉,可能结果不尽如人意。有时候,我想让自己去为一个人改变,或许自我感觉这样的成功率要高一些吧。的确,这样确实让我改变了很多,但是,有时候又觉得,那样似乎又不是我想要的我了。 过去的都过去了,现在的我和过去的我并没有什么不好的,以后的我也许和现在的我会有很多巨大的差异,但是又有什么实质的不同吗? 我该做什么 我该做什么呢,这个问题感觉我并不清楚吧。 有时候,觉得学习课本是必须的,但是,又不是很想学,总是由于某些客观的因素被动的学习着某些知识,终是考完就忘光的节奏。 有时候呢,觉得我需要学习更多计算机相关的知识,但是又发现食之无味,兴趣大减,倒不如学习ACM相关的一些知识。 也有时候,想去打游戏,但是,打着打着,还是觉得无趣,或许一个人的游戏终不算是游戏吧。 其实呢,现在也还是不错的,每天学一学ACM的知识,也挂一挂游戏,虽然对专业的教的知识已经丧失了以前的兴趣,但是也还是会去看一看。 就这样吧,这样就可以了。 卡题了,码不动了]]></content>
</entry>
<entry>
<title><![CDATA[CDOJ 811 GCD]]></title>
<url>%2F2016%2F12%2F08%2FCDOJ%20811%20GCD%2F</url>
<content type="text"><![CDATA[建议先看这篇文章.很显然,所求的式子可以化为$$\sum_{i=1}^{n}i^{k}\left(2\phi\left(\frac{n}{i}\right)-1\right)$$其中,$\phi\left(\frac{n}{i}\right)$是欧拉函数的前缀和,这个可以用刚刚提到的那篇文章的方法在$o\left ( n^{\frac{2}{3}} \right )$复杂度求解。而左边那个$k$次方前缀和可以直接百度求值,或者暴力插值求解。反正就这样搞搞就行了,智障少年写不动题解了 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133//created by missever#include<bits/stdc++.h>#define MAX 1000000007using namespace std;typedef long long LL;const int maxn = 1e7+5;const int rev = (MAX + 1) >> 1;bool flag[maxn];int phi[maxn],pri[maxn];int cnt = 0,k;LL sum[maxn];LL a[8],b[8],c[8];map<LL,LL> p;void Get_phi(){ phi[1] = 1; sum[1] = 1; for(int i = 2; i < maxn; i++) { if(!flag[i]) { pri[cnt++] = i; phi[i] = i - 1; } for(int j = 0; j < cnt; j++) { if(i * pri[j] > maxn) break; flag[i * pri[j]] = true; if(i % pri[j] == 0) { phi[i * pri[j]] = pri[j] * phi[i]; break; } else phi[i * pri[j]] = (pri[j] - 1) * phi[i]; } sum[i] = (sum[i - 1] + phi[i]) % MAX; }}LL Get_sumpri(LL n){ if(n < maxn) return sum[n]; if(p.find(n) != p.end()) return p[n]; LL i,j; LL s = n % MAX * ((n + 1) % MAX) % MAX * rev % MAX; for(i = 2; i <= n; i = j + 1) { j = n / (n / i); s = (s - (j - i + 1) % MAX * Get_sumpri(n / i) % MAX) % MAX; } s = (s + MAX) % MAX; p[n] = s; return s;}void extend_Euclid(LL a, LL b, LL &x, LL &y){ if(b == 0) { x = 1; y = 0; return; } extend_Euclid(b, a % b, x, y); LL tmp = x; x = y; y = tmp - (a / b) * y;}LL Inv(LL a, LL b){ LL x, y; extend_Euclid(a, b, x, y); return (x % b + b) % b;}LL Get_kpow(LL n){ if(n <= k + 1) return a[n]; LL i,j; LL s = 0,f; for(i = 0;i <= k + 1; i++) { f = 1; for(j = 0;j <= k + 1; j++) { if(j != i) f = (n - j) % MAX * f % MAX; } s = (s + f * c[i] % MAX) % MAX; } return (s + MAX) % MAX;}LL Get_ans(LL n){ LL i,j; LL s = 0,f = 0,g; for(i = 1; i <= n; i = j + 1) { j = n / (n / i); g = Get_kpow(j); s = (s + (Get_sumpri(n / i) * 2LL - 1LL) % MAX * ((g - f + MAX) % MAX) % MAX) % MAX; f = g; } return (s + MAX) % MAX;}int main(){ Get_phi(); LL n; int i,j; scanf("%lld",&n); scanf("%d",&k); b[0] = 1; for(i = 1;i <= k + 1; i++) { a[i] = i; for(j = 1;j < k; j++) a[i] = a[i] * i % MAX; a[i] = (a[i] + a[i - 1]) % MAX; b[i] = b[i - 1] * i % MAX; } for(i = 1;i <= k + 1; i++) { c[i] = a[i] * Inv(b[i] * b[k + 1 - i] % MAX,MAX) % MAX; if((k + 1 - i) & 1) c[i] = -c[i]; } printf("%lld\n",Get_ans(n)); return 0;}]]></content>
</entry>
<entry>
<title><![CDATA[初记、]]></title>
<url>%2F2016%2F12%2F07%2Fthe-first-article%2F</url>
<content type="text"><![CDATA[终于把博客搭起来了,虽然还有很多地方没有完善……先mark一下吧、、]]></content>
</entry>
</search>