2018 Multi-University Training Contest 5

贱贱补不动题了T^T

Always Online

发现之前的点双都在乱写,就顺便花了点时间重造板子

考虑一个仙人掌,割要么是一条树边要么是环上两条边,注意到切环时其中一条一定是环上最小的

跑一遍Tarjan搞出所有点双,把环上最小边切了权值加到环上其他边上,这样转化为树上问题

树上做法,类似于Kruskal从大到小合并边,两边的子树大小乘积为这条边的贡献

由于这里的贡献带了异或,按位考虑即可,注意答案暴了ll

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef unsigned long long ull;
  4 const int maxn = 1e5 + 10;
  5 const int maxm = 2e5 + 10;
  6 int u[maxm], v[maxm], w[maxm];
  7 vector<int> G[maxn], E;
  8 bool cmp(int i, int j) {
  9     return w[i] > w[j];
 10 }
 11 
 12 // BCC
 13 stack<int> S;
 14 vector<int> bcc[maxm];
 15 int bcc_cnt, bccno[maxm];
 16 int dfs_clock, dfn[maxn], low[maxn], iscut[maxn];
 17 void dfs(int x, int fe) { // fe 表示父边 id
 18     low[x] = dfn[x] = ++dfs_clock;
 19     int ch = 0;
 20     for (int i = 0; i < G[x].size(); ++i) {
 21         int e = G[x][i];
 22         if (e == fe) continue;
 23         int y = u[e] == x ? v[e] : u[e];
 24         if (!dfn[y]) {
 25             S.push(e);
 26             ch++, dfs(y, e); // 注意是 e
 27             low[x] = min(low[x], low[y]);
 28             if (low[y] >= dfn[x]) {
 29                 iscut[x] = 1;
 30                 bcc_cnt++;
 31                 while (1) {
 32                     int t = S.top();
 33                     S.pop();
 34                     bccno[t] = bcc_cnt;
 35                     bcc[bcc_cnt].push_back(t);
 36                     if (t == e) break;
 37                 }
 38             }
 39         } else if (dfn[y] < dfn[x]) {
 40             low[x] = min(low[x], dfn[y]);
 41             S.push(e);
 42         }
 43     }
 44     if (!fe && ch == 1) iscut[x] = 0;
 45 }
 46 void find_bcc(int n, int m) {
 47     dfs_clock = bcc_cnt = 0;
 48     for (int i = 0; i <= n; ++i) dfn[i] = iscut[i] = 0;
 49     for (int i = 0; i <= m; ++i) bccno[i] = 0, bcc[i].clear();
 50     for (int i = 1; i <= n; ++i) if (!dfn[i]) dfs(i, 0);
 51 }
 52 
 53 int fa[maxn], r[maxn][31][2];
 54 void init(int n) {
 55     for(int i = 0; i <= n; ++i) {
 56         fa[i] = i;
 57         for(int j = 0; j <= 30; ++j) {
 58             r[i][j][1] = (i & (1 << j)) ? 1 : 0;
 59             r[i][j][0] = 1 - r[i][j][1];
 60         }
 61     }
 62 }
 63 int Find(int x) {
 64     return fa[x] == x ? x : fa[x] = Find(fa[x]);
 65 }
 66 void Union(int x, int y) {
 67     x = Find(x), y = Find(y);
 68     if(x == y) return;
 69     fa[x] = y;
 70     for(int j = 0; j <= 30; ++j)
 71         for(int k = 0; k <= 1; ++k) r[y][j][k] += r[x][j][k];
 72 }
 73 
 74 int main() {
 75     int T;
 76     scanf("%d", &T);
 77     while(T--) {
 78         int n, m;
 79         scanf("%d %d", &n, &m);
 80         for(int i = 1; i <= n; ++i) G[i].clear();
 81         for(int i = 1; i <= m; ++i) {
 82             scanf("%d %d %d", u + i, v + i, w + i);
 83             G[u[i]].push_back(i);
 84             G[v[i]].push_back(i);
 85         }
 86         find_bcc(n, m);
 87         E.clear();
 88         for(int i = 1; i <= bcc_cnt; ++i) {
 89             if(bcc[i].size() == 1) {
 90                 E.push_back(bcc[i][0]);
 91                 continue;
 92             }
 93             int mi = 1000000000, p;
 94             for(int j = 0; j < bcc[i].size(); ++j) {
 95                 int x = bcc[i][j];
 96                 if(w[x] < mi) mi = w[x], p = j;
 97             }
 98             for(int j = 0; j < bcc[i].size(); ++j) {
 99                 if(j == p) continue;
100                 int x = bcc[i][j];
101                 E.push_back(x), w[x] += mi;
102             }
103         }
104         init(n);
105         ull ans = 0;
106         sort(E.begin(), E.end(), cmp);
107         for(int i = 0; i < E.size(); ++i) {
108             int x = E[i], U = Find(u[x]), V = Find(v[x]), W = w[x];
109             for(int j = 0; j <= 30; ++j) {
110                 if(W & (1 << j)) ans += ((ull) r[U][j][0] * r[V][j][0] + (ull) r[U][j][1] * r[V][j][1]) * (1 << j);
111                 else ans += ((ull) r[U][j][0] * r[V][j][1] + (ull) r[U][j][1] * r[V][j][0]) * (1 << j);
112             }
113             Union(U, V);
114         }
115         printf("%llu\n", ans);
116     }
117     return 0;
118 }
Aguin

 

Beautiful Now

暴力全排列竟然过了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 vector< vector<int> > P[11];
 4 vector<int> num[11];
 5 
 6 int main() {
 7     int fac = 1;
 8     for(int i = 1; i <= 9; ++i) {
 9         fac *= i;
10         vector<int> v;
11         for(int j = 1; j <= i; ++j) v.push_back(j);
12         for(int j = 0; j < fac; ++j) {
13             int vis[11] = {0}, cnt = 0;
14             for(int k = 1; k <= i; ++k) {
15                 if(vis[k]) continue;
16                 int p = k;
17                 while(!vis[p]) vis[p] = 1, p = v[p - 1], cnt++;
18                 cnt--;
19             }
20             P[i].push_back(v);
21             num[i].push_back(cnt);
22             next_permutation(v.begin(), v.end());
23         }
24     }
25     int T;
26     scanf("%d", &T);
27     while(T--) {
28         int n, k;
29         scanf("%d %d", &n, &k);
30         if(n == 1000000000) {
31             puts("1000000000 1000000000");
32             continue;
33         }
34         int mi = n, ma = n, b = 0, d[11] = {0};
35         while(n) d[++b] = n % 10, n /= 10;
36         for(int i = 0; i < P[b].size(); ++i) {
37             if(num[b][i] > k) continue;
38             if(b > 1 && d[P[b][i][b - 1]] == 0) continue;
39             int x = 0;
40             for(int j = b - 1; j >= 0; --j) x = x * 10 + d[P[b][i][j]];
41             mi = min(x, mi), ma = max(x, ma);
42         }
43         printf("%d %d\n", mi, ma);
44     }
45     return 0;
46 }
Aguin

 

Call It What You Want

传说中的Easy题

分圆多项式有$(1 - x^n) = \prod_{d|n}\Phi_{d}(x)$,莫比乌斯反演一下$\Phi_{n}(x)=\prod_{d|n}(1 - x^{\frac{n}{d}})^{\mu(d)}$

题面说了$\Phi_{n}(x)$是$\varphi(n)$次多项式,而一个数最多只有$6$个不同的素因子,考虑莫比乌斯函数不为$0$的项,求单个$\Phi_{n}(x)$最多做$2^6$次多项式乘除法

而每次乘除的都是一个只有两项的多项式,可以直接在模$x^{\varphi(n) + 1}$下算,用类似背包的写法,单次就是$\varphi(n)$的复杂度

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef pair<int, int> pii;
  4 const int maxn = 1e5 + 10;
  5 
  6 int tot, check[maxn], prime[maxn], phi[maxn], mu[maxn];
  7 void Sieve() {
  8     tot = 0;
  9     phi[1] = mu[1] = 1;
 10     memset(check, 0, sizeof(check));
 11     for(int i = 2; i < maxn; ++i) {
 12         if(!check[i]) prime[++tot] = i, phi[i] = i - 1, mu[i] = -1;
 13         for(int j = 1; j <= tot; ++j) {
 14             if(i * prime[j] >= maxn) break;
 15             check[i * prime[j]] = 1;
 16             if(i % prime[j] == 0) {
 17                 phi[i * prime[j]] = phi[i] * prime[j];
 18                 mu[i * prime[j]] = 0;
 19                 break;
 20             }
 21             else {
 22                 phi[i * prime[j]] = phi[i] * (prime[j] - 1);
 23                 mu[i * prime[j]] = -mu[i];
 24             }
 25         }
 26     }
 27 }
 28 
 29 vector<int> fac[maxn], Mul[maxn], Div[maxn];
 30 vector< vector<pii> > v;
 31 vector<int> id;
 32 bool cmp(int i, int j) {
 33     for(int k = 0; ; ++k) {
 34         if(k == v[i].size()) return v[j][k].second > 0;
 35         if(k == v[j].size()) return v[i][k].second < 0;
 36         if(v[i][k].first > v[j][k].first) return v[i][k].second < 0;
 37         if(v[i][k].first < v[j][k].first) return v[j][k].second > 0;
 38         if(v[i][k].second != v[j][k].second) return v[i][k].second < v[j][k].second;
 39     }
 40 }
 41 void solve(int n) {
 42     vector<int> p(phi[n] + 1, 0);
 43     p[0] = 1;
 44     for(int i = 0; i < Mul[n].size(); ++i) {
 45         int k = Mul[n][i];
 46         for(int j = phi[n]; j - k >= 0; --j) p[j] -= p[j - k];
 47     }
 48     for(int i = 0; i < Div[n].size(); ++i) {
 49         int k = Div[n][i];
 50         for(int j = 0; j + k <= phi[n]; ++j) p[j + k] += p[j];
 51     }
 52     vector<pii> t;
 53     for(int i = phi[n]; i >= 0; --i) {
 54         if(p[i] == 0) continue;
 55         t.push_back(pii(i, p[i]));
 56     }
 57     v.push_back(t);
 58 }
 59 
 60 void p(vector<pii> &t) {
 61     stringstream s;
 62     s << "(";
 63     int flag = 0;
 64     for(int k = 0; k < t.size(); ++k) {
 65         int x = t[k].first, y = t[k].second;
 66         if(y < 0) s << "-";
 67         else if(flag) s << "+";
 68         if(abs(y) != 1) s << abs(y);
 69         if(x > 0) s << "x";
 70         else if(abs(y) == 1) s << "1";
 71         if(x > 1) s << "^" << x;
 72         flag = 1;
 73     }
 74     s << ")";
 75     cout << s.str();
 76 }
 77 
 78 int main() {
 79     Sieve();
 80     for(int i = 1; i <= 100000; ++i) {
 81         for(int j = i; j <= 100000; j += i) fac[j].push_back(i);
 82         if(!mu[i]) continue;
 83         for(int j = i; j <= 100000; j += i) {
 84             if(mu[i] == 1) Mul[j].push_back(j / i);
 85             else Div[j].push_back(j / i);
 86         }
 87     }
 88     int T;
 89     scanf("%d", &T);
 90     while(T--) {
 91         int n;
 92         scanf("%d", &n);
 93         v.clear(), id.clear();
 94         for(int i = 0; i < fac[n].size(); ++i) if(fac[n][i] > 1) solve(fac[n][i]);
 95         for(int i = 0; i < v.size(); ++i) id.push_back(i);
 96         sort(id.begin(), id.end(), cmp);
 97         printf("(x-1)");
 98         for(int i = 0; i < v.size(); ++i) p(v[id[i]]);
 99         puts("");
100     }
101     return 0;
102 }
Aguin

 

Daylight

答案为到$u$不超过$w$的点加到$v$不超过$w$的点减去到$u$,$v$都不超过的点,即减去的部分是到$u$,$v$中点不超过$w - \frac{dis(u, v)}{2}$的点

注意到中点可能不是一个节点而是某一条边的中点,即问题可归结为两种询问,询问距离点$u$不超过$k$的点数和询问距离边$u-v$不超过$k$的点数

对于第一个经典问题,首先树分治并维护点分树,每个重心用一个不定长数组记录子树中到重心距离为$k$的点数,同时记录到点分树父亲距离为$k$的点数

对于每次询问,从询问点往点分树根部爬,每次计算该重心子树中的贡献,并减去会与父亲重复计算的部分

对于第二个问题,注意到$u$与$v$是相邻点,故在点分树上必然一个点是另一个点的祖先,那么从点分树上深度较大的点出发会经过所有包含$u$或者$v$的子树

对于询问,只要在每个重心时将询问点取$u$与$v$中距离重心较近的一个即可

卡常有意思吗加了一堆inline过了

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 // fastIO
  5 namespace fastIO {
  6 #define BUF_SIZE 100000
  7     //fread -> read
  8     bool IOerror = 0;
  9     inline char nc() {
 10         static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
 11         if(p1 == pend) {
 12             p1 = buf;
 13             pend = buf + fread(buf, 1, BUF_SIZE, stdin);
 14             if(pend == p1) {
 15                 IOerror = 1;
 16                 return -1;
 17             }
 18         }
 19         return *p1++;
 20     }
 21     inline bool blank(char ch) {
 22         return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
 23     }
 24     inline void read(int &x) {
 25         char ch;
 26         while(blank(ch = nc()));
 27         if(IOerror)
 28             return;
 29         for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
 30     }
 31 #undef BUF_SIZE
 32 };
 33 using namespace fastIO;
 34 
 35 
 36 const int maxn = 1e5 + 10;
 37 vector<int> G[maxn];
 38 
 39 // LCA
 40 int dfs_clock;
 41 int dep[maxn], tid[maxn << 1], dfn[maxn];
 42 int fa[maxn][21];
 43 // 进出时间都要记录,数组需要开两倍
 44 void dfs(int x, int f) {
 45     fa[x][0] = f;
 46     dep[x] = dep[f] + 1;
 47     tid[++dfs_clock] = x, dfn[x] = dfs_clock;
 48     for (int i = 0; i < G[x].size(); ++i) {
 49         int to = G[x][i];
 50         if (to == f) continue;
 51         dfs(to, x);
 52         tid[++dfs_clock] = x; // 每个点出栈时加入父亲
 53     }
 54 }
 55 int lg2[maxn << 1], rmq[maxn << 1][21];
 56 void init(int n) {
 57     // LCA-ST
 58     lg2[0] = -1;
 59     for (int i = 1; i <= dfs_clock; ++i) lg2[i] = lg2[i >> 1] + 1;
 60     for (int i = 1; i <= dfs_clock; ++i) rmq[i][0] = tid[i];
 61     for (int j = 1; (1 << j) <= dfs_clock; ++j) {
 62         for (int i = 1; i + (1 << j) - 1 <= dfs_clock; ++i) {
 63             int ls = rmq[i][j - 1], rs = rmq[i + (1 << (j - 1))][j - 1];
 64             rmq[i][j] = dep[ls] < dep[rs] ? ls : rs;
 65         }
 66     }
 67     // 树上倍增
 68     for (int j = 1; (1 << j) <= n; ++j)
 69         for (int i = 1; i <= n; ++i) fa[i][j] = fa[fa[i][j - 1]][j - 1];
 70 }
 71 inline int LCA(int x, int y) {
 72     if (dfn[x] > dfn[y]) swap(x, y);
 73     int k = lg2[dfn[y] - dfn[x] + 1];
 74     int ls = rmq[dfn[x]][k], rs = rmq[dfn[y] - (1 << k) + 1][k];
 75     return dep[ls] < dep[rs] ? ls : rs;
 76 }
 77 inline int dis(int x, int y) {
 78     int lca = LCA(x, y);
 79     return dep[x] + dep[y] - dep[lca] * 2;
 80 }
 81 
 82 struct V {
 83     vector<int> c;
 84     V(int n = 0) {vector<int>(n + 1, 0).swap(c);}
 85     inline void modify(int i, int x) {
 86         if (i >= 0 && i < c.size()) c[i] += x;
 87     }
 88     inline void sum() {
 89         for (int i = 1; i < c.size(); ++i) c[i] += c[i - 1];
 90     }
 91     inline int query(int i) {
 92         if (i >= 0) return c[min((int) c.size() - 1, i)];
 93         return 0;
 94     }
 95 } T[maxn], FT[maxn];
 96 
 97 // D&C
 98 int vis[maxn], sz[maxn];
 99 void SZ(int x, int f) {
100     sz[x] = 1;
101     for (int i = 0; i < G[x].size(); ++i) {
102         int to = G[x][i];
103         if (vis[to] || to == f) continue;
104         SZ(to, x), sz[x] += sz[to];
105     }
106 }
107 int tot, mi, rt;
108 // 重心:最大子树最小
109 void RT(int x, int f) {
110     int ma = tot - sz[x];
111     for (int i = 0; i < G[x].size(); ++i) {
112         int to = G[x][i];
113         if (vis[to] || to == f) continue;
114         RT(to, x), ma = max(ma, sz[to]);
115     }
116     if (ma < mi) mi = ma, rt = x;
117 }
118 // 处理点分树上父亲至子树中的点最近距离
119 int F[maxn], D[maxn], mf[maxn];
120 void MF(int x, int f, int C) {
121     mf[C] = min(mf[C], dis(F[C], x));
122     for (int i = 0; i < G[x].size(); ++i) {
123         int to = G[x][i];
124         if (vis[to] || to == f) continue;
125         MF(to, x, C);
126     }
127 }
128 void INS(int x, int f, int C) {
129     T[C].modify(dis(x, C), 1);
130     if (F[C]) FT[C].modify(dis(x, F[C]) - mf[C], 1);
131     for (int i = 0; i < G[x].size(); ++i) {
132         int to = G[x][i];
133         if (vis[to] || to == f) continue;
134         INS(to, x, C);
135     }
136 }
137 void build(int x, int f) {
138     SZ(x, 0);
139     tot = mi = sz[x], RT(x, 0), x = rt;
140     F[x] = f, D[x] = D[f] + 1;
141     T[x] = V(tot);
142     // FT[x].query(i) 询问的是子树中距离父亲 i + mf[x] 的点权值和
143     if (f) FT[x] = V(tot), mf[x] = dis(x, f), MF(x, 0, x);
144     INS(x, 0, x), T[x].sum(), FT[x].sum();
145     vis[x] = 1;
146     for (int i = 0; i < G[x].size(); ++i) {
147         int to = G[x][i];
148         if (vis[to]) continue;
149         build(to, x);
150     }
151 }
152 int q1(int x, int y, int k) {
153     int ret = T[x].query(k - dis(x, y));
154     int fd = dis(F[x], y);
155     // 询问一直处理到根,即便中间有点贡献为零
156     if (F[x]) ret += q1(F[x], y, k) - FT[x].query(k - fd - mf[x]);
157     return ret;
158 }
159 int q2(int x, int u, int v, int k) {
160     int ret = T[x].query(k - min(dis(x, u), dis(x, v)));
161     int fd = min(dis(F[x], u), dis(F[x], v));
162     if (F[x]) ret += q2(F[x], u, v, k) - FT[x].query(k - fd - mf[x]);
163     return ret;
164 }
165 
166 int anc(int x, int d) {
167     for(int i = 20; i >= 0; --i)
168         if(d >= (1 << i)) d -= (1 << i), x = fa[x][i];
169     return x;
170 }
171 int m1(int u, int v) {
172     int d = dis(u, v);
173     int lca = LCA(u, v);
174     if(dep[u] - dep[lca] > dep[v] - dep[lca]) return anc(u, d / 2);
175     return anc(v, d / 2);
176 }
177 typedef pair<int, int> pii;
178 pii m2(int u, int v) {
179     int lca = LCA(u, v);
180     int d = dis(u, v), dl = d / 2, dr = d - dl;
181     int ml = dep[u] - dep[lca] >= dl ? anc(u, dl) : anc(v, dr);
182     int mr = dep[u] - dep[lca] >= dr ? anc(u, dr) : anc(v, dl);
183     return pii(ml, mr);
184 }
185 
186 int main() {
187     int T;
188     read(T);
189     while(T--) {
190         int n, m;
191         read(n), read(m);
192         for(int i = 1; i <= n; ++i) G[i].clear(), vis[i] = 0;
193         for(int i = 2; i <= n; ++i) {
194             int u, v;
195             read(u), read(v);
196             G[u].push_back(v);
197             G[v].push_back(u);
198         }
199         dfs_clock = 0, dfs(1, 0), init(n);
200         build(1, 0);
201         int ans = 0;
202         while(m--) {
203             int u, v, w;
204             read(u), read(v), read(w);
205             u = (u + ans) % n + 1;
206             v = (v + ans) % n + 1;
207             w = (w + ans) % n;
208             int d = dis(u, v);
209             ans = q1(u, u, w) + q1(v, v, w);
210             if(d <= w + w) {
211                 if(d & 1) {
212                     pii t = m2(u, v);
213                     u = t.first, v = t.second;
214                     ans -= q2(D[u] > D[v] ? u : v, u, v, w - d / 2 - 1);
215                 }
216                 else {
217                     int mid = m1(u, v);
218                     ans -= q1(mid, mid, w - d / 2);
219                 }
220             }
221             printf("%d\n", ans);
222         }
223     }
224     return 0;
225 }
Aguin

 

Everything Has Changed

为什么不用判断优弧劣弧呢呢

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double pi = acos(-1);
 4 int sqr(int x) {return x * x;}
 5 
 6 int main() {
 7     int T;
 8     scanf("%d", &T);
 9     while(T--) {
10         int m, R;
11         scanf("%d %d", &m, &R);
12         double ans = 2 * R * pi;
13         while(m--) {
14             int x, y, r;
15             scanf("%d %d %d", &x, &y, &r);
16             if(sqr(x) + sqr(y) >= sqr(R + r)) continue;
17             if(sqr(x) + sqr(y) < sqr(R - r)) continue;
18             double d = sqrt(sqr(x) + sqr(y));
19             double theta1 = 2 * acos((sqr(R) + sqr(x) + sqr(y) - sqr(r)) / (2 * R * d));
20             double theta2 = 2 * acos((sqr(r) + sqr(x) + sqr(y) - sqr(R)) / (2 * r * d));
21             ans -= theta1 * R - theta2 * r;
22         }
23         printf("%.8f\n", ans);
24     }
25     return 0;
26 }
Aguin

 

Fireflies

前面一堆著名结论我是不知道的,直接从转变为$\sum_{i = 1}^{n}x_{i} = \lfloor \frac{1}{2}\sum_{i = 1}^{n}(p_{i} + 1)  \rfloor$开始做

首先容斥成$\sum_{I \subseteq J} (-1) ^{|I|} C_{M - 1 - \sum_{i \in I} p_{i}}^{n - 1}$,组合数是关于$\sum_{i \in I} p_{i}$的$n - 1$次多项式

可以先暴力把组合数拆开,求出多项式的系数,然后分别考虑每一项的贡献,这样就可以折半枚举一边,再用二项式定理合起来

广义组合数是有负数定义的,但是考虑实际情况组合数不为零需要满足$M - \sum_{i \in I} p_{i} \geq n$

所以折半的两边要先按大小排序,枚举一半的时候用双指针维护另一半的幂的和

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll mod = 1e9 + 7;
 5 
 6 ll fp(ll a, ll b) {
 7     ll ret = 1;
 8     while (b) {
 9         if (b & 1) ret = ret * a % mod;
10         a = a * a % mod;
11         b >>= 1;
12     }
13     return ret;
14 }
15 ll inv(ll x) {
16     return fp(x, mod - 2);
17 }
18 
19 ll sum[2][1 << 17];
20 int id[2][1 << 17], cnt[2][1 << 17];
21 bool cmp1(int i, int j) {
22     return sum[0][i] < sum[0][j];
23 }
24 bool cmp2(int i, int j) {
25     return sum[1][i] > sum[1][j];
26 }
27 
28 int main() {
29     ll c[44][44] = {0};
30     for(int i = 0; i < 44; ++i) c[i][0] = c[i][i] = 1;
31     for(int i = 2; i < 44; ++i)
32         for(int j = 1; j < i; ++j)
33             c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
34     int T;
35     scanf("%d", &T);
36     while(T--) {
37         int n;
38         scanf("%d", &n);
39         ll M = 0, p[35], a[35] = {1}, t = 1;
40         for(int i = 1; i <= n; ++i) scanf("%lld", p + i), M += p[i] + 1;
41         M /= 2;
42         for(int i = 0; i < n - 1; ++i) {
43             t = t * (i + 1) % mod;
44             for(int j = i + 1; j > 0; --j) a[j] = mod - a[j - 1];
45             a[0] = 0;
46             for(int j = 0; j <= i; ++j) a[j] = (a[j] + a[j + 1] * (mod + 1 - M % mod + i)) % mod;
47         }
48         t = inv(t);
49         for(int i = 0; i <= n - 1; ++i) a[i] = a[i] * t % mod;
50         int l = n / 2, r = n - l;
51         for(int i = 0; i < (1 << l); ++i) {
52             id[0][i] = i, sum[0][i] = cnt[0][i] = 0;
53             for(int j = 0; j < l; ++j)
54                 if(i & (1 << j)) sum[0][i] = sum[0][i] + p[j + 1], cnt[0][i]++;
55         }
56         sort(id[0], id[0] + (1 << l), cmp1);
57         for(int i = 0; i < (1 << r); ++i) {
58             id[1][i] = i, sum[1][i] = cnt[1][i] = 0;
59             for(int j = 0; j < r; ++j)
60                 if(i & (1 << j)) sum[1][i] = sum[1][i] + p[l + j + 1], cnt[1][i]++;
61         }
62         sort(id[1], id[1] + (1 << r), cmp2);
63         int pos = 0;
64         ll ans = 0, s[2][44] = {0};
65         for(int i = 0; i < (1 << r); ++i) {
66             int x = id[1][i];
67             if(sum[1][x] > M - n) continue;
68             while(pos < (1 << l) && sum[0][id[0][pos]] + sum[1][x] <= M - n) {
69                 int y = id[0][pos];
70                 ll tmp = 1;
71                 for(int j = 0; j < n; ++j) {
72                     s[cnt[0][y] % 2][j] = (s[cnt[0][y] % 2][j] + tmp) % mod;
73                     tmp = tmp * (sum[0][y] % mod) % mod;
74                 }
75                 pos++;
76             }
77             for(int j = 0; j < n; ++j) {
78                 ll tmp = 0, mul = 1;
79                 for(int k = 0; k <= j; ++k) {
80                     tmp = (tmp + mul * c[j][k] % mod * s[cnt[1][x] % 2][j - k]) % mod;
81                     tmp = (tmp + mod - mul * c[j][k] % mod * s[(cnt[1][x] % 2) ^ 1][j - k] % mod) % mod;
82                     mul = mul * (sum[1][x] % mod) % mod;
83                 }
84                 ans = (ans + tmp * a[j]) % mod;
85             }
86         }
87         printf("%lld\n", ans);
88     }
89     return 0;
90 }
Aguin

 

Glad You Came

反着用ST表

考虑正常ST表,首先预处理的时候每个长度为$2^k$的区间的$\max$是两个重叠的长度为$2^{k-1}$的子区间传递过来的,询问的时候只要找两个长度不大于$log_{2}(r - l + 1)$的区间合并

反过来就是每次修改对两个长度不大于$log_{2}(r - l + 1)$的区间标记,后处理的时候把每个长度为$2^k$的区间的标记下传到两个重叠的长度为$2^{k-1}$的子区间

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned int ui;
 4 
 5 ui X, Y, Z;
 6 ui f() {
 7     X = X ^ (X << 11);
 8     X = X ^ (X >> 4);
 9     X = X ^ (X << 5);
10     X = X ^ (X >> 14);
11     ui W = X ^ (Y ^ Z);
12     X = Y;
13     Y = Z;
14     Z = W;
15 }
16 
17 const int maxn = 1e5 + 10;
18 int rmq[maxn][20], lg[maxn];
19 void init(int n) {
20     for (int j = 0; j <= lg[n]; j++)
21         for (int i = 1; i + (1 << j) - 1 <= n; i++)
22             rmq[i][j] = 0;
23 }
24 void modify(int l, int r, int v) {
25     int k = lg[r - l + 1];
26     rmq[l][k] = max(rmq[l][k], v);
27     rmq[r - (1 << k) + 1][k] = max(rmq[r - (1 << k) + 1][k], v);
28 }
29 void cal(int n) {
30     for (int j = lg[n]; j >= 1; j--)
31         for (int i = 1; i + (1 << j) - 1 <= n; i++)
32             rmq[i][j - 1] = max(rmq[i][j - 1], rmq[i][j]), rmq[i + (1 << j - 1)][j - 1] = max(
33                     rmq[i + (1 << j - 1)][j - 1], rmq[i][j]);
34 }
35 
36 int main() {
37     lg[0] = -1;
38     for(int i = 1; i < maxn; ++i) lg[i] = lg[i / 2] + 1;
39     int T;
40     scanf("%d", &T);
41     for(int i = 1; i <= T; ++i) {
42         int n, m;
43         scanf("%d %d %u %u %u", &n, &m, &X, &Y, &Z);
44         init(n);
45         for(int i = 1; i <= m; ++i) {
46             int l = f() % n + 1, r = f() % n + 1, v = f() % (1 << 30);
47             if(l > r) swap(l, r);
48             modify(l, r, v);
49         }
50         cal(n);
51         long long ans = 0;
52         for(int i = 1; i <= n; ++i) ans ^= 1ll * i * rmq[i][0];
53         printf("%lld\n", ans);
54     }
55     return 0;
56 }
Aguin

 

Hills And Valleys

$f[i][j]$表示前缀$[1...i]$最后一个数是$j$的最长不减子序列,$g[i][j][k][l]$表示前缀$[1...i]$第一段(递增)末尾是数字$j$,第二段(递减)开头是数字$k$,末尾是数字$l$的最长子序列

注意到需要满足$j \leq l \leq k$所以实际状态没有那么多,第一维滚动数组优化掉,同时从$f$转移到$g$的时候记录一下左端点,第三段(递增)和第一段一样后缀预处理好

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5 + 10;
 4 int f[maxn][10], g[10][10][10], h[10][10][10], lg[10][10][10], lh[10][10][10];
 5 int p[maxn][10];
 6 int A[maxn];
 7 char s[maxn];
 8 
 9 int main() {
10     int T;
11     scanf("%d", &T);
12     while(T--) {
13         int n;
14         scanf("%d %s", &n, s + 1);
15         for(int i = 1; i <= n; ++i) A[i] = s[i] - '0';
16         for(int i = 0; i <= n + 1; ++i)
17             for(int j = 0; j < 10; ++j) f[i][j] = p[i][j] = 0;
18         for(int i = n; i >= 1; --i) {
19             for(int j = 0; j < 10; ++j) p[i][j] = p[i + 1][j];
20             for(int j = 9; j >= A[i]; --j) p[i][A[i]] = max(p[i][A[i]], p[i + 1][j] + 1);
21         }
22         for(int j = 0; j < 10; ++j) for(int k = 9; k >= j; --k) for(int l = j; l <= k; ++l) g[j][k][l] = lg[j][k][l] = 0;
23         int m = 0, L = 0, R = 0;
24         for(int i = 1; i <= n; ++i) {
25             for(int j = 0; j < 10; ++j) f[i][j] = f[i - 1][j];
26             for(int j = 0; j <= A[i]; ++j) f[i][A[i]] = max(f[i][A[i]], f[i - 1][j] + 1);
27             for(int j = 0; j < 10; ++j) for(int k = 9; k >= j; --k) for(int l = j; l <= k; ++l)
28                 h[j][k][l] = g[j][k][l], lh[j][k][l] = lg[j][k][l];
29             for(int j = 0; j <= A[i]; ++j) if(f[i - 1][j] + 1 > g[j][A[i]][A[i]]) g[j][A[i]][A[i]] = f[i - 1][j] + 1, lg[j][A[i]][A[i]] = i;
30             for(int j = 0; j <= A[i]; ++j) for(int k = 9; k >= A[i]; --k) for(int l = k; l >= A[i]; --l)
31                 if(h[j][k][l] + 1 > g[j][k][A[i]]) g[j][k][A[i]] = h[j][k][l] + 1, lg[j][k][A[i]] = lh[j][k][l];
32             for(int j = 0; j <= A[i]; ++j) for(int k = 9; k >= A[i]; --k) for(int l = 9; l >= k; --l)
33                 if(g[j][k][A[i]] + p[i + 1][l] > m) m = g[j][k][A[i]] + p[i + 1][l], L = lg[j][k][A[i]], R = i;
34         }
35         if(R && !L) L = 1;
36         if(!L && !R) int x = 1 / 0;
37         printf("%d %d %d\n", m, L, R);
38     }
39     return 0;
40 }
Aguin

 

Innocence

题解有点没说清楚阿……

考虑没有下界约束的情况,这个做法很多,但是为了后面方便,先考虑一个暴力数位打牌的做法

先把问题拆分成$log$个,从高位往低位,找到第一个位$b$满足$N$个数中至少有一个此位与上界$R$不相等

如果不存在这样的$b$,那么这$N$个数都与上界相等,这个情况单独考虑即可

找到$b$后,要$dp$出所有满足至少一个数此位小于上界的方案数,状态为$f[i][j][k]$表示取了$i$个数,$j = 0/1$表示前$i$个数中是否有此位小于上界,$k$表示前$i$个数此位异或值

转移的时候枚举新加的一个数,第$b$位是$0/1$,若此位填的数与上界相等,那么后缀填数方案要满足不大于上界,否则后面可以填任意数

注意到每增加一个数的转移是一样的,可以对第一维做矩阵快速幂转移

再考虑有下界的情况,可以暴力容斥转化为没有下界的情况,即至少$0$个数小于下界$-$至少$1$个数小于下界$+$至少$2$个数下于下界……

也就是说新加入一个数的时候,要考虑这个数的约束是仅小于上界,还是同时小于下界两种情况转移,状态也要多加一维$f[i][j][k][l]$其中$l$表示$i$个数中强制要求小于下界的数有$l$个

这样状态数就炸了,但是很容易发现容斥的时候正负号只和$l$的奇偶有关,所以状态存$l \ mod \ 2$就可以了,依然可以矩阵快速幂把$i$优化掉

询问时对于每个$K$,枚举一下$b$统计方案,并单独处理$b$不存在的情况

两个容易忽视的坑点是$K$大于最高位要直接输出$0$,$R$为$0$要特判……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll mod = 1e9 + 7;
 5 // f[i][j][k] 是否卡上界 当前0/1 <L数目%2
 6 
 7 const int maxm = 8;
 8 struct Mat {
 9     ll a[maxm][maxm];
10     Mat() {memset(a, 0, sizeof(a));}
11     void E() {
12         for(int i = 0; i < maxm; ++i)
13             for(int j = 0; j < maxm; ++j)
14                 a[i][j] = i == j ? 1 : 0;
15     }
16 } f[30];
17 void Mul(Mat A, Mat B, Mat& C) {
18     for(int i = 0; i < maxm; ++i)
19         for(int j = 0; j < maxm; ++j)
20             C.a[i][j] = 0;
21     for(int i = 0; i < maxm; ++i) {
22         for(int j = 0; j < maxm; ++j) {
23             if(!A.a[i][j]) continue;
24             for(int k = 0; k < maxm; ++k) {
25                 if(!B.a[j][k]) continue;
26                 C.a[i][k] = (C.a[i][k] + A.a[i][j] * B.a[j][k]) % mod;
27             }
28         }
29     }
30 }
31 void Pow(Mat& A, ll n) {
32     Mat ret; ret.E();
33     while(n) {
34         if(n & 1) Mul(ret, A, ret);
35         Mul(A, A, A), n >>= 1;
36     }
37     A = ret;
38 }
39 
40 int main() {
41     int T;
42     scanf("%d", &T);
43     while(T--) {
44         int N, L, R, Q;
45         scanf("%d %d %d %d", &N, &L, &R, &Q);
46         int mx = 0;
47         while((1 << mx) <= R) ++mx;
48         for(int b = 0; b < mx; ++b) {
49             f[b] = Mat();
50             int rb = ((1 << b) & R) ? 1 : 0, lb = L && ((1 << b) & (L - 1)) ? 1 : 0;
51             for(int i = 0; i <= 1; ++i) for(int j = 0; j <= 1; ++j) for(int k = 0; k <= 1; ++k) {
52                 int msk = (i << 2) + (j << 1) + k;
53                 for(int nb = 0; nb <= 1; ++nb) {
54                     if(rb || !nb) {
55                         int ni = i && (rb == nb), nj = j ^ nb, nk = k;
56                         int nmsk = (ni << 2) + (nj << 1) + nk;
57                         f[b].a[nmsk][msk] += nb < rb ? (i ? 1 : (1 << b)) : ((R & ((1 << b) - 1)) + 1);
58                     }
59                     if(L && (lb || !nb)) {
60                         int ni = i && (lb == nb), nj = j ^ nb, nk = k ^ 1;
61                         int nmsk = (ni << 2) + (nj << 1) + nk;
62                         f[b].a[nmsk][msk] += nb < lb ? (i ? 1 : (1 << b)) : (((L - 1) & ((1 << b) - 1)) + 1);
63                     }
64                 }
65             }
66             Pow(f[b], N);
67         }
68         while(Q--) {
69             int K;
70             scanf("%d", &K);
71             if(K >= (1 << mx)) {puts("0"); continue;}
72             if(R == 0) {puts("1"); continue;}
73             ll ans = 0;
74             int o = N & 1, r = o ? R : 0, l = L ? r ^ R ^ (L - 1) : 0;
75             int okr = 1, okl = 1;
76             for(int b = mx - 1; b >= 0; --b) {
77                 int nr = (r & (1 << b)) ? 1 : 0;
78                 int nl = (l & (1 << b)) ? 1 : 0;
79                 int nk = (K & (1 << b)) ? 1 : 0;
80                 if(okr) ans = (ans + f[b].a[nk << 1][4]) % mod;
81                 if(L && okl) ans = (ans + mod - f[b].a[(nk << 1) + 1][4]) % mod;
82                 if(nr != nk) okr = 0;
83                 if(nl != nk) okl = 0;
84             }
85             if(r == K) ans = (ans + f[0].a[4 + ((K & 1) << 1)][4]) % mod;
86             if(L && l == K) ans = (ans + mod - f[0].a[4 + ((K & 1) << 1) + 1][4]) % mod;
87             printf("%lld\n", ans);
88         }
89     }
90     return 0;
91 }
Aguin

 

Just So You Know

题意有点迷,一次$Conjecture$本质上是询问目标串是否在一个子集中,这个子集是可以任意选取的

考虑一个简单版本,一个多重集,等概率选择一个数,按同样的规则每次猜测该数是否在某子集中,合理决策使询问期望最少

一次询问根据回答的$Yes/No$实际上是将一个集合划分为两部分,即询问的子集和它的补集,至上而下划分便形成了一棵二叉决策树

那么使询问期望最小,等同于让每个点的深度与概率乘积之和最小,本质上是求一个哈夫曼树,也就是经典的合并果子问题

于是原问题可以看成两部分,第一部分是统计出现$i$次的子串数目,然后就转化为上面的简化问题,需要做一个哈夫曼树

第一部分可牛逼了,首先需要一个代表国内最牛逼后缀数组水平的$SA-IS$,这个可以去陈敏锐小给给的博客那蒯一个

然后建一个小根的笛卡尔树,就可以线性统计出现$i$次的子串数目,然后好像笛卡尔树这里深搜爆栈了很难受只好换了个丑丑的$BFS$

统计完后开始合并果子,由于一共有$\frac{n(n + 1)}{2}$个子串,所以出现次数相同的要一起合并

对于某个频数的子串,如果有偶数个就直接自己合并,否则留一个出来和后面比它大的合并

对于频数小于$n$的子串,从小到大边扫边合并就行了,发现会合并出大小为$O(n^2)$级别的节点出来

但是由于总串数的限制,大于$n$的结点数是$O(n)$级别的,所以一旦合并出来大于$n$,就丢到一个队列里,最后做一次普通的合并果子即可

btw感觉dls这题代码合并的时候是$O(nlogn)$的……

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 
  5 const int N = 1e6 + 10;
  6 namespace SA {
  7     int sa[N], rk[N], ht[N], s[N<<1], t[N<<1], p[N], cnt[N], cur[N];
  8 #define pushS(x) sa[cur[s[x]]--] = x
  9 #define pushL(x) sa[cur[s[x]]++] = x
 10 #define inducedSort(v) fill_n(sa, n, -1); fill_n(cnt, m, 0);                  \
 11     for (int i = 0; i < n; i++) cnt[s[i]]++;                                  \
 12     for (int i = 1; i < m; i++) cnt[i] += cnt[i-1];                           \
 13     for (int i = 0; i < m; i++) cur[i] = cnt[i]-1;                            \
 14     for (int i = n1-1; ~i; i--) pushS(v[i]);                                  \
 15     for (int i = 1; i < m; i++) cur[i] = cnt[i-1];                            \
 16     for (int i = 0; i < n; i++) if (sa[i] > 0 &&  t[sa[i]-1]) pushL(sa[i]-1); \
 17     for (int i = 0; i < m; i++) cur[i] = cnt[i]-1;                            \
 18     for (int i = n-1;  ~i; i--) if (sa[i] > 0 && !t[sa[i]-1]) pushS(sa[i]-1)
 19     void sais(int n, int m, int *s, int *t, int *p) {
 20         int n1 = t[n-1] = 0, ch = rk[0] = -1, *s1 = s+n;
 21         for (int i = n-2; ~i; i--) t[i] = s[i] == s[i+1] ? t[i+1] : s[i] > s[i+1];
 22         for (int i = 1; i < n; i++) rk[i] = t[i-1] && !t[i] ? (p[n1] = i, n1++) : -1;
 23         inducedSort(p);
 24         for (int i = 0, x, y; i < n; i++) if (~(x = rk[sa[i]])) {
 25                 if (ch < 1 || p[x+1] - p[x] != p[y+1] - p[y]) ch++;
 26                 else for (int j = p[x], k = p[y]; j <= p[x+1]; j++, k++)
 27                         if ((s[j]<<1|t[j]) != (s[k]<<1|t[k])) {ch++; break;}
 28                 s1[y = x] = ch;
 29             }
 30         if (ch+1 < n1) sais(n1, ch+1, s1, t+n, p+n1);
 31         else for (int i = 0; i < n1; i++) sa[s1[i]] = i;
 32         for (int i = 0; i < n1; i++) s1[i] = p[sa[i]];
 33         inducedSort(s1);
 34     }
 35     template<typename T>
 36     int mapCharToInt(int n, const T *str) {
 37         int m = *max_element(str, str+n);
 38         fill_n(rk, m+1, 0);
 39         for (int i = 0; i < n; i++) rk[str[i]] = 1;
 40         for (int i = 0; i < m; i++) rk[i+1] += rk[i];
 41         for (int i = 0; i < n; i++) s[i] = rk[str[i]] - 1;
 42         return rk[m];
 43     }
 44 // Ensure that str[n] is the unique lexicographically smallest character in str.
 45     template<typename T>
 46     void suffixArray(int n, const T *str) {
 47         int m = mapCharToInt(++n, str);
 48         sais(n, m, s, t, p);
 49         for (int i = 0; i < n; i++) rk[sa[i]] = i;
 50         for (int i = 0, h = ht[0] = 0; i < n-1; i++) {
 51             int j = sa[rk[i]-1];
 52             while (i+h < n && j+h < n && s[i+h] == s[j+h]) h++;
 53             if (ht[rk[i]] = h) h--;
 54         }
 55     }
 56 };
 57 
 58 int a[N], *h;
 59 int fa[N], st[N], l[N], r[N], vis[N];
 60 ll tot, f[N], sz[N];
 61 void dfs(int x, int fa) {
 62     int len = h[x];
 63     if(fa) len -= h[fa];
 64     sz[x] = 2;
 65     if(l[x]) dfs(l[x], x), sz[x] += sz[l[x]] - 1;
 66     if(r[x]) dfs(r[x], x), sz[x] += sz[r[x]] - 1;
 67     f[sz[x]] += len, tot -= sz[x] * len;
 68 }
 69 
 70 vector<int> v;
 71 queue<int> q;
 72 queue<ll> q1, q2;
 73 int main() {
 74     int T;
 75     scanf("%d", &T);
 76     while(T--) {
 77         ll n;
 78         scanf("%lld", &n);
 79         for(int i = 0; i < n; ++i) scanf("%d", a + i), a[i]++;
 80         a[n] = 0;
 81         SA :: suffixArray(n, a);
 82         h = SA :: ht + 1;
 83         int top = 0;
 84         for (int i = 1; i < n; ++i) l[i] = r[i] = vis[i] = 0;
 85         for (int i = 1; i < n; ++i) {
 86             int k = top;
 87             while (k > 0 && h[st[k - 1]] > h[i]) --k;
 88             if (k) r[st[k - 1]] = i;
 89             if (k < top) l[i] = st[k];
 90             st[k++] = i;
 91             top = k;
 92         }
 93         for (int i = 1; i < n; ++i) vis[l[i]] = vis[r[i]] = 1;
 94         int rt = 0;
 95         for (int i = 1; i < n; ++i) if (!vis[i]) rt = i;
 96         for (int i = 1; i <= n; ++i) f[i] = 0;
 97         tot = n * (n + 1) / 2;
 98         while(!q.empty()) q.pop();
 99         q.push(rt);
100         fa[rt] = 0;
101         v.clear();
102         while(!q.empty()) {
103             int x = q.front(); q.pop();
104             v.push_back(x);
105             if(l[x]) q.push(l[x]), fa[l[x]] = x;
106             if(r[x]) q.push(r[x]), fa[r[x]] = x;
107         }
108         for(int i = v.size() - 1; i >= 0; --i) {
109             int x = v[i], len = h[x];
110             if(fa[x]) len -= h[fa[x]];
111             sz[x] = 2;
112             if(l[x]) sz[x] += sz[l[x]] - 1;
113             if(r[x]) sz[x] += sz[r[x]] - 1;
114             f[sz[x]] += len, tot -= sz[x] * len;
115         }
116         f[1] = tot;
117         ll ans = 0, o = 0;
118         for(int i = 1; i <= n; ++i) {
119             if(!f[i]) continue;
120             if(o) {
121                 f[i]--;
122                 if(i + o <= n) f[i + o]++;
123                 else q1.push(i + o);
124                 ans += i + o, o = 0;
125             }
126             if(f[i] & 1) o = i, f[i]--;
127             if(!f[i]) continue;
128             if(i + i <= n) f[i + i] += f[i] / 2, ans += f[i] * i;
129             else for(int j = 1; j <= f[i] / 2; ++j) q1.push(i + i), ans += i + i;
130         }
131         while(!q1.empty() || !q2.empty()) {
132             ll x = 0, y = 0;
133             if(o) x = o, o = 0;
134             else {
135                 if(!q1.empty() && !q2.empty()) {
136                     if(q1.front() < q2.front()) x = q1.front(), q1.pop();
137                     else x = q2.front(), q2.pop();
138                 }
139                 else if(!q1.empty()) x = q1.front(), q1.pop();
140                 else x = q2.front(), q2.pop();
141             }
142             if(q1.empty() && q2.empty()) break;
143             if(!q1.empty() && !q2.empty()) {
144                 if(q1.front() < q2.front()) y = q1.front(), q1.pop();
145                 else y = q2.front(), q2.pop();
146             }
147             else if(!q1.empty()) y = q1.front(), q1.pop();
148             else y = q2.front(), q2.pop();
149             ans += x + y;
150             q2.push(x + y);
151         }
152         ll t = n * (n + 1) / 2;
153         ll g = __gcd(ans, t);
154         ans /= g, t /= g;
155         printf("%lld", ans);
156         if(t > 1) printf("/%lld", t);
157         puts("");
158     }
159     return 0;
160 }
Aguin

 

Kaleidoscope

好像不会计数哇T^T

 

Lost In The Echo

论文都没有的题不补><

posted @ 2018-08-08 08:26  Aguin  阅读(388)  评论(5编辑  收藏  举报