SDOI2016 R1 解题报告 bzoj4513~bzoj4518
储能表
将n, m分解为二进制,考虑一个log(n)层的trie树,n会在这颗trie树上走出了一个路径,因为 行数 $ \le n$,所以在n的二进制路径上,每次往1走的时候,与m计算贡献,m同样处理,$O(Tlog(n)log(m))$
当然可以数位dp, $f_{i, n, m, k}$分别代表考虑到第i位,与n, m, k的大小关系,不是很好写,就写了上面的方法。
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (int i = a; i <= b; i++) 3 #define drep(i, a, b) for (int i = a; i >= b; i--) 4 #define REP(i, a, b) for (int i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define xx first 8 #define yy second 9 using namespace std; 10 typedef long long ll; 11 typedef pair<int, int> pii; 12 typedef unsigned long long ull; 13 const int inf = 0x3f3f3f3f; 14 const ll INF = 0x3f3f3f3f3f3f3f3fll; 15 template <typename T> void Max(T& a, T b) { if (b > a) a = b; } 16 //********************************* 17 18 ll n, m, k, mod; 19 20 ll POW(ll base, ll num) { 21 ll ret = 1; 22 while (num) { 23 if (num & 1) ret = ret * base % mod; 24 base = base * base % mod; 25 num >>= 1; 26 } 27 return ret; 28 } 29 30 ll calc(ll st, ll num) { 31 if (st < 0) { num += st; st = 0; } 32 if (num <= 0) return 0; 33 ll t1 = 2 * st + num - 1; 34 if (t1 & 1) num >>= 1; 35 else t1 >>= 1; 36 return t1 % mod * (num % mod) % mod; 37 } 38 ll solve(ll x, ll y, ll i, ll j) { 39 ll ret(0); 40 if (j > i) swap(i, j), swap(x, y); 41 ll z = x ^ (y ^ (y & ((1ll << i) - 1))); 42 ret = calc(z - k, 1ll << i); 43 return (ret * ((1ll << j) % mod)) % mod; 44 } 45 int main() { 46 /* 47 freopen("table.in", "r", stdin); 48 freopen("table.out", "w", stdout); 49 */ 50 int T; scanf("%d", &T); 51 while (T--) { 52 scanf("%lld%lld%lld%lld", &n, &m, &k, &mod); 53 54 ll x(0); 55 ll ans(0); 56 drep(i, 62, 0) if (n >> i & 1) { 57 ll y(0); 58 drep(j, 62, 0) if (m >> j & 1) { 59 (ans += solve(x, y, i, j)) %= mod; 60 y |= 1ll << j; 61 } 62 x |= 1ll << i; 63 } 64 65 printf("%lld\n", ans); 66 } 67 }
数字配对
网络流,首先这个图不是奇环,这个图如果有环,那么结构应该是对称的?【我也不是非常清楚,求教。。。】
把费用和容量连成边,进行二分图染色,一直增广到费用加上当前费用小于0为止,别忘了考虑最后一次的流量。
#include <bits/stdc++.h> #define rep(i, a, b) for (int i = a; i <= b; i++) #define drep(i, a, b) for (int i = a; i >= b; i--) #define REP(i, a, b) for (int i = a; i < b; i++) #define pb push_back #define mp make_pair #define xx first #define yy second using namespace std; typedef long long ll; typedef pair<int, int> pii; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; template <typename T> void Max(T& a, T b) { if (b > a) a = b; } //********************************* const int maxn = 205; struct Ed { int u, v, c; ll w; int nx; Ed() {} Ed(int _u, int _v, int _c, ll _w, int _nx) : u(_u), v(_v), c(_c), w(_w), nx(_nx) {} } E[maxn * maxn << 1]; int G[maxn], edtot = 1; void addedge(int u, int v, int c, ll w) { E[++edtot] = Ed(u, v, c, w, G[u]); G[u] = edtot; E[++edtot] = Ed(v, u, 0, -w, G[v]); G[v] = edtot; } bool judge(int num) { int sqr = sqrt(num); if (num == 1) return 0; rep(i, 2, sqr) if (num % i == 0) return 0; return 1; } int s, t; int knd[maxn]; int n; int a[maxn], b[maxn], c[maxn]; void dfs(int x, int col) { knd[x] = col; for (int i = 1; i <= n; i++) if (knd[i] == -1 && (a[i] % a[x] == 0 && judge(a[i] / a[x]) || a[x] % a[i] == 0 && judge(a[x] / a[i]))) dfs(i, col ^ 1); } ll dis[maxn]; int pre[maxn]; bool spfa() { rep(i, 1, n + 2) dis[i] = -INF; static int que[maxn]; int qh(0), qt(0); static int vis[maxn]; memset(vis, 0, sizeof(vis)); vis[que[++qt] = s] = 1; dis[s] = 0; while (qh != qt) { int x = que[++qh]; if (qh == maxn - 1) qh = 0; for (int i = G[x]; i; i = E[i].nx) if (E[i].c && dis[E[i].v] < dis[x] + E[i].w) { dis[E[i].v] = dis[x] + E[i].w; pre[E[i].v] = i; if (!vis[E[i].v]) { vis[que[++qt] = E[i].v] = 1; if (qt == maxn - 1) qt = 0; } } vis[x] = 0; } return dis[t] != -INF; } int ans; ll cost; bool mcf() { int flow = inf; ll nm(0); for (int i = pre[t]; i; i = pre[E[i].u]) { flow = min(flow, E[i].c); nm += E[i].w; } if (nm * flow + cost < 0) { ans += cost / -nm; return 0; } ans += flow, cost += nm * flow; for (int i = pre[t]; i; i = pre[E[i].u]) E[i].c -= flow, E[i ^ 1].c += flow; return 1; } int main() { /* freopen("pair.in", "r", stdin); freopen("pair.out", "w", stdout); */ scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i); rep(i, 1, n) scanf("%d", b + i); rep(i, 1, n) scanf("%d", c + i); memset(knd, -1, sizeof(knd)); rep(i, 1, n) if (knd[i] == -1) dfs(i, 0); rep(i, 1, n) rep(j, 1, n) if (knd[i] == 1 && knd[j] == 0) { if (a[i] % a[j] == 0 && judge(a[i] / a[j]) || a[j] % a[i] == 0 && judge(a[j] / a[i])) addedge(i, j, min(b[i], b[j]), 1ll * c[i] * c[j]); } s = n + 1, t = n + 2; rep(i, 1, n) if (knd[i]) addedge(s, i, b[i], 0); else addedge(i, t, b[i], 0); while (spfa()) if (!mcf()) break; cout << ans << endl; }
游戏
树链剖分,考虑树链剖分时,每一次的修改均是连续的一段,我们对每一段维护标记$ax + b$x为当前点到这一段起点的距离。
那么假如有新的标记$Ax + B$,我们讨论$Ax + B <= ax + b$的情况,如果影响范围在mid的一边,就把新的标记向一边推,如果新的标记覆盖了多余一半,我们将新标记放在当前节点上,将原来的标记向不足mid的部分下推。
可以说是把标记永久化了。
复杂度为$O(mlog^{3}n)$,树链剖分两个log,标记一次最多下推log层。
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (int i = a; i <= b; i++) 3 #define drep(i, a, b) for (int i = a; i >= b; i--) 4 #define REP(i, a, b) for (int i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define xx first 8 #define yy second 9 using namespace std; 10 typedef long long ll; 11 typedef pair<int, int> pii; 12 typedef unsigned long long ull; 13 const int inf = 0x3f3f3f3f; 14 const ll INF = 0x3f3f3f3f3f3f3f3fll; 15 template <typename T> void Max(T& a, T b) { if (b > a) a = b; } 16 //********************************* 17 18 const int maxn = 100005; 19 20 struct Ed { 21 int u, v, w, nx; Ed() {} 22 Ed(int _u, int _v, int _w, int _nx) : 23 u(_u), v(_v), w(_w), nx(_nx) {} 24 } E[maxn << 1]; 25 int G[maxn], edtot; 26 27 void addedge(int u, int v, int w) { 28 E[++edtot] = Ed(u, v, w, G[u]); 29 G[u] = edtot; 30 E[++edtot] = Ed(v, u, w, G[v]); 31 G[v] = edtot; 32 } 33 34 int pre[maxn], dep[maxn], son[maxn], sz[maxn]; 35 ll dis[maxn]; 36 int f[maxn][18]; 37 int dfs(int x, int fa) { 38 pre[x] = fa, dep[x] = dep[fa] + 1; f[x][0] = fa; 39 for (int i = 1; i <= 17; i++) f[x][i] = f[f[x][i - 1]][i - 1]; 40 son[x] = 0, sz[x] = 1; 41 for (int i = G[x]; i; i = E[i].nx) if (E[i].v != fa) { 42 dis[E[i].v] = dis[x] + E[i].w; 43 sz[x] += dfs(E[i].v, x); 44 if (sz[E[i].v] > sz[son[x]]) son[x] = E[i].v; 45 } 46 return sz[x]; 47 } 48 int pos[maxn], inv[maxn], top[maxn], ndtot; 49 void repos(int x, int tp) { 50 top[x] = tp; pos[x] = ++ndtot; inv[ndtot] = x; 51 if (son[x]) repos(son[x], tp); 52 for (int i = G[x]; i; i = E[i].nx) if (E[i].v != son[x] && E[i].v != pre[x]) repos(E[i].v, E[i].v); 53 } 54 55 int LCA(int l, int r) { 56 if (dep[l] < dep[r]) swap(l, r); 57 int t = dep[l] - dep[r]; 58 drep(i, 17, 0) if (t >> i & 1) l = f[l][i]; 59 if (l == r) return l; 60 drep(i, 17, 0) if (f[l][i] != f[r][i]) l = f[l][i], r = f[r][i]; 61 return f[l][0]; 62 } 63 64 ll Min[maxn << 2]; 65 ll A[maxn << 2], B[maxn << 2], Flag[maxn << 2]; 66 void pushup(int o, int l, int r) { 67 if (Flag[o]) Min[o] = min(B[o], A[o] * (dis[inv[r]] - dis[inv[l]]) + B[o]); 68 if (l != r) Min[o] = min(Min[o], min(Min[o << 1], Min[o << 1 | 1])); 69 } 70 void giveFlag(int o, int l, int r, ll a, ll b) { 71 if (!Flag[o]) { A[o] = a, B[o] = b; Flag[o] = 1; } 72 else { 73 int mid = l + r >> 1; ll len = dis[inv[mid + 1]] - dis[inv[l]]; 74 if (A[o] == a || l == r) B[o] = min(B[o], b); 75 else if (a > A[o] && B[o] < b); 76 else if (a > A[o] && B[o] >= b) { 77 ll d = (B[o] - b) / (a - A[o]); 78 if (d < len) giveFlag(o << 1, l, mid, a, b); 79 else { 80 swap(A[o], a), swap(B[o], b); 81 giveFlag(o << 1 | 1, mid + 1, r, a, b + a * len); 82 } 83 } 84 else if (a < A[o] && B[o] > b) swap(A[o], a), swap(B[o], b); 85 else if (a < A[o] && B[o] <= b) { 86 ll d = (B[o] - b - 1) / (a - A[o]) + 1; 87 if (d >= len) giveFlag(o << 1 | 1, mid + 1, r, a, b + a * len); 88 else { 89 swap(A[o], a), swap(B[o], b); 90 giveFlag(o << 1, l, mid, a, b); 91 } 92 } 93 } 94 95 pushup(o, l, r); 96 } 97 98 void modify(int o, int l, int r, int ql, int qr, ll a, ll b) { 99 if (ql <= l && r <= qr) { 100 giveFlag(o, l, r, a, b + a * (dis[inv[l]] - dis[inv[ql]])); 101 return; 102 } 103 104 int mid = l + r >> 1; 105 if (ql <= mid) modify(o << 1, l, mid, ql, qr, a, b); 106 if (qr > mid) modify(o << 1 | 1, mid + 1, r, ql, qr, a, b); 107 pushup(o, l, r); 108 } 109 110 int n; 111 void modify2(int tar, int x, ll a, ll b) { 112 while (top[tar] != top[x]) { 113 int F = top[x]; 114 modify(1, 1, n, pos[F], pos[x], a, b + a * (dis[F] - dis[tar])); 115 x = pre[F]; 116 } 117 118 modify(1, 1, n, pos[tar], pos[x], a, b); 119 } 120 121 void modify(int l, int r, ll a, ll b) { 122 int lca = LCA(l, r); 123 modify2(lca, l, -a, b + a * (dis[l] - dis[lca])); 124 modify2(lca, r, a, b + a * (dis[l] - dis[lca])); 125 } 126 127 ll query(int o, int l, int r, int ql, int qr) { 128 ll ret = INF; 129 if (Flag[o]) { 130 int L = max(l, ql), R = min(r, qr); 131 ret = min(A[o] * (dis[inv[L]] - dis[inv[l]]) + B[o], A[o] * (dis[inv[R]] - dis[inv[l]]) + B[o]); 132 } 133 134 if (ql <= l && r <= qr) return min(ret, Min[o]); 135 else { 136 int mid = l + r >> 1; 137 if (ql <= mid) ret = min(ret, query(o << 1, l, mid, ql, qr)); 138 if (qr > mid) ret = min(ret, query(o << 1 | 1, mid + 1, r, ql, qr)); 139 } 140 return ret; 141 } 142 143 ll solve(int l, int r) { 144 ll ret = INF; 145 while (top[l] != top[r]) { 146 if (dep[top[l]] < dep[top[r]]) swap(l, r); 147 ret = min(ret, query(1, 1, n, pos[top[l]], pos[l])); 148 l = pre[top[l]]; 149 } 150 if (dep[l] < dep[r]) swap(l, r); 151 ret = min(ret, query(1, 1, n, pos[r], pos[l])); 152 153 return ret; 154 } 155 156 int main() { 157 /* 158 freopen("game.in", "r", stdin); 159 freopen("game.out", "w", stdout); 160 */ 161 int m; scanf("%d%d", &n, &m); 162 REP(i, 1, n) { 163 int u, v, w; scanf("%d%d%d", &u, &v, &w); 164 addedge(u, v, w); 165 } 166 167 dfs(1, 1), repos(1, 1); 168 169 REP(i, 0, maxn << 2) Min[i] = 123456789123456789ll; 170 171 while (m--) { 172 int op; scanf("%d", &op); 173 if (op == 1) { 174 int u, v, a, b; scanf("%d%d%d%d", &u, &v, &a, &b); 175 modify(u, v, a, b); 176 } 177 else { 178 int s, t; scanf("%d%d", &s, &t); 179 printf("%lld\n", solve(s, t)); 180 } 181 } 182 183 return 0; 184 }
生成魔咒
后缀数组,将字符串反过来,维护一个set,每次加入的字符串找到位置,计算贡献。
#include <bits/stdc++.h> #define rep(i, a, b) for (register int i = a; i <= b; i++) #define drep(i, a, b) for (register int i = a; i >= b; i--) #define REP(i, a, b) for (int i = a; i < b; i++) #define pb push_back #define mp make_pair #define clr(x) memset(x, 0, sizeof(x)) #define xx first #define yy second using namespace std; typedef long long ll; typedef pair<int, int> pii; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; //******************************** const int maxn = 100005; int a[maxn], hsh[maxn], cd; int sa[maxn], t[maxn], t2[maxn], c[maxn], n; void build_sa(int m) { int *x = t, *y = t2; rep(i, 0, m) c[i] = 0; rep(i, 1, n) c[x[i] = a[i]]++; rep(i, 1, m) c[i] += c[i - 1]; drep(i, n, 1) sa[c[x[i]]--] = i; for (int k = 1; k <= n; k <<= 1) { int p = 0; rep(i, n - k + 1, n) y[++p] = i; rep(i, 1, n) if (sa[i] > k) y[++p] = sa[i] - k; rep(i, 0, m) c[i] = 0; rep(i, 1, n) c[x[y[i]]]++; rep(i, 1, m) c[i] += c[i - 1]; drep(i, n, 1) sa[c[x[y[i]]]--] = y[i]; swap(x, y); p = 1; x[sa[1]] = 0; rep(i, 2, n) x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++; if (p >= n) break; m = p; } } int rnk[maxn], height[maxn]; void build_height() { int k(0); rep(i, 1, n) rnk[sa[i]] = i; rep(i, 1, n) { if (k) k--; int j = sa[rnk[i] - 1]; while (a[j + k] == a[i + k]) k++; height[rnk[i]] = k; } } int Min[maxn][20], Log[maxn]; void build_st() { Log[1] = 0; rep(i, 2, n) { Log[i] = Log[i - 1]; if (1 << Log[i] + 1 == i) Log[i]++; } drep(i, n, 1) { Min[i][0] = height[i]; for (int j = 1; i + (1 << j) - 1 <= n; j++) Min[i][j] = min(Min[i][j - 1], Min[i + (1 << j - 1)][j - 1]); } } int query(int l, int r) { int len = r - l + 1, k = Log[len]; return min(Min[l][k], Min[r - (1 << k) + 1][k]); } int main() { scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i), hsh[i] = a[i]; cd = n; sort(hsh + 1, hsh + 1 + n), cd = unique(hsh + 1, hsh + 1 + cd) - hsh - 1; rep(i, 1, n) a[i] = lower_bound(hsh + 1, hsh + 1 + cd, a[i]) - hsh; rep(i, 1, n / 2) swap(a[i], a[n - i + 1]); a[++n] = 0; a[n + 1] = inf; build_sa(cd); build_height(); build_st(); ll ans(0); set <int> S; S.insert(-inf), S.insert(inf); drep(i, n - 1, 1) { set<int> :: iterator H = S.lower_bound(rnk[i]), P = S.upper_bound(rnk[i]); int A, B; if (H != S.begin()) A = *--H; else A = -inf; B = *P; if (A != -inf) ans += query(min(rnk[i], A) + 1, max(rnk[i], A)); if (B != inf) ans += query(min(rnk[i], B) + 1, max(rnk[i], B)); if (A != -inf && B != inf) ans -= query(min(A, B) + 1, max(A, B)); printf("%lld\n", 1ll * (n - i) * (n - i - 1) / 2 + n - i - ans); S.insert(rnk[i]); } return 0; }
排列计数
组合数*错排数
$f_{n} = (n - 1)(f_{n - 1} + f_{n - 2})$
1 #include <bits/stdc++.h> 2 #define rep(i, a, b) for (long long i = a; i <= b; i++) 3 #define drep(i, a, b) for (long long i = a; i >= b; i--) 4 #define REP(i, a, b) for (long long i = a; i < b; i++) 5 #define pb push_back 6 #define mp make_pair 7 #define xx first 8 #define yy second 9 using namespace std; 10 typedef long long ll; 11 typedef pair<int, int> pii; 12 const int inf = 0x3f3f3f3f; 13 const ll INF = 0x3f3f3f3f3f3f3f3fll; 14 template <typename T> void Max(T& a, T b) { if (b > a) a = b; } 15 //********************************* 16 17 const int maxn = 1000005; 18 const int mod = 1e9 + 7; 19 20 ll fac[maxn]; 21 ll f[maxn]; 22 void prepare() { 23 f[0] = 1, f[1] = 0, f[2] = 1; 24 rep(n, 3, 1000000) f[n] = ((n - 1) * (n - 1) % mod * f[n - 2] % mod + (n - 1) * (n - 2) % mod * f[n - 3] % mod) % mod; 25 26 fac[0] = 1; 27 rep(n, 1, 1000000) fac[n] = fac[n - 1] * n % mod; 28 } 29 30 ll POW(ll base, int num) { 31 ll ret = 1; 32 while (num) { 33 if (num & 1) ret = ret * base % mod; 34 base = base * base % mod; 35 num >>= 1; 36 } 37 return ret; 38 } 39 ll C(int n, int m) { 40 ll ret = fac[n]; 41 ret = ret * POW(fac[n - m], mod - 2) % mod; 42 ret = ret * POW(fac[m], mod - 2) % mod; 43 return ret; 44 } 45 int main() { 46 prepare(); 47 int T; scanf("%d", &T); 48 while (T--) { 49 int n, m; scanf("%d%d", &n, &m); 50 if (n < m) puts("0"); 51 else printf("%lld\n", C(n, m) * f[n - m] % mod); 52 } 53 return 0; 54 }
征途
$s^{2} = \frac{\sum\limits_{i = 1}^{m}(x_{i} - \overline{x})^{2}}{m}$,将$(x_{i} - \overline{x})^{2}$展开,会发现我们其实要最小化$\sum\limits_{i = 1}^{m}x_{i}^{2}$
设$f_{i,j}$代表dp到第i位(包括i),是第j段的最小平方和。
那么$f_{i,j} = min(f_{k,j - 1}) + (s_{i}-s_{k})^{2}$, s为前缀和。
固定j以后发现只与k有关,斜率优化即可。
#include <bits/stdc++.h> #define rep(i, a, b) for (int i = a; i <= b; i++) #define drep(i, a, b) for (int i = a; i >= b; i--) #define REP(i, a, b) for (int i = a; i < b; i++) #define pb push_back #define mp make_pair #define xx first #define yy second using namespace std; typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; template <typename T> void Max(T& a, T b) { if (b > a) a = b; } //********************************* const int maxn = 3005; ll f[maxn], s[maxn], a[maxn]; inline ll p(ll num) { return num * num; } struct HH { ll x, y; }; double k(HH A, HH B) { return (double)(A.y - B.y) / (A.x - B.x); } int main() { int n, m; scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%lld", a + i), s[i] = s[i - 1] + a[i]; rep(i, 1, n) f[i] = p(s[i]); rep(j, 2, m) { static HH que[maxn]; int qh = 1, qt(0); rep(i, 1, n) { HH t = (HH) {s[i], f[i] + p(s[i])}; while (qt > qh && k(que[qt], t) < k(que[qt - 1], que[qt])) qt--; que[++qt] = t; while (qt > qh && k(que[qh], que[qh + 1]) < 2 * s[i]) qh++; f[i] = que[qh].y - p(que[qh].x) + p(s[i] - que[qh].x); } } cout << m * f[n] - p(s[n]) << endl; return 0; }