bzoj刷题记录5.6-5.10
来源:互联网 发布:未成年av淘宝 编辑:程序博客网 时间:2024/06/05 03:54
bzoj刷题记录5.6-5.10
bzoj3944: Sum
学习一个杜教筛。比较好的资料有:
http://blog.csdn.net/skywalkert/article/details/50500009
以及任之洲Orz的论文。
考虑
根据神奇的公式:
化简并使用通用处理技术得到:
然后就可以下底分块了。可以证明
#include <bits/stdc++.h>using namespace std;const int MAXN = 2500001;int phi[MAXN], mu[MAXN], prime[MAXN], top = 0, not_prime[MAXN];long long sphi[MAXN], smu[MAXN];map<long long, long long> dp, d2;void get_prime(int n){ mu[1] = phi[1] = 1; for (register int i = 2; i <= n; i++) { if (!not_prime[i]) prime[++top] = i, mu[i] = -1, phi[i] = i-1; for (register int j = 1; j <= top && i*prime[j] <= n; j++) { not_prime[i*prime[j]] = 1; if (i%prime[j] == 0) { mu[i*prime[j]] = 0; phi[i*prime[j]] = phi[i]*prime[j]; break; } mu[i*prime[j]] = mu[i]*mu[prime[j]]; phi[i*prime[j]] = phi[i]*phi[prime[j]]; } } for (register int i = 1; i <= n; i++) sphi[i] = sphi[i-1]+phi[i], smu[i] = smu[i-1]+mu[i];//, dp[i] = sphi[i], d2[i] = smu[i];}struct query { long long x, y;};inline query sum_phi(long long n){ if (n<MAXN) return (query){sphi[n], smu[n]}; if (dp.count(n)) return (query){dp[n], d2[n]}; register long long ans = n*(n+1)/2, a2 = 1; query q; for (register long long i = 2, last; i <= n; i = last+1) { last = n/(n/i); q = sum_phi(n/i); ans -= (last-i+1)*q.x; a2 -= (last-i+1)*q.y; } dp[n] = ans, d2[n] = a2; return (query){ans, a2};}int main(){ get_prime(MAXN-1); long long n; int T; scanf("%d", &T); while (T--) { scanf("%lld", &n); query q = sum_phi(n); cout << q.x << " " << q.y << endl; } return 0;}
虽然不是bzoj但同一主题也放上来吧
51nod1237: 1237 最大公约数之和 V3
比较有意思的题目。
后面的东西是不是很眼熟?还记得xx的gcd中推得的结论:
令
因此原式就是:
然后就可以用杜教筛做
#include <iostream>#include <map>#include <cstdio>#include <cstring>using namespace std;const int MAXN = 2500001;int prime[MAXN], top = 0, not_prime[MAXN], phi[MAXN], sphi[MAXN];long long s[MAXN], n;long long mod = 1000000007ll;map<long long, long long> dp;void get_prime(int n){ phi[1] = 1; for (int i = 2; i <= n; i++) { if (!not_prime[i]) prime[++top] = i, phi[i] = i-1; for (int j = 1; j <= top && prime[j]*i <= n; j++) { not_prime[i*prime[j]] = 1; if (i%prime[j] == 0) { phi[i*prime[j]] = phi[i]*prime[j]; break; } phi[i*prime[j]] = phi[i]*phi[prime[j]]; } } for (int i = 1; i <= n; i++) sphi[i] = (sphi[i-1]+phi[i])%mod;}long long sum(long long n){ if (n < MAXN) return sphi[n]; if (dp.count(n)) return dp[n]; long long ans = n%mod*(n%mod+1)/2%mod; for (register long long p = 2, last; p <= n; p = last+1) { last = n/(n/p); (ans -= sum(n/p)*(last-p+1)) %= mod; } return dp[n] = (ans+mod)%mod;}long long power(long long n){ long long ans = 1, b = 2; for (int i = 0; i <= 63; i++) { if (n&(1ll<<i)) (ans *= b) %= mod; (b *= b) %= mod; } return ans;}int main(){ scanf("%lld", &n); get_prime(MAXN-1); long long ans = 0; for (register long long k = 1, last; k <= n; k = last+1) { last = n/(n/k); (ans += (k+last)%mod*(last-k+1)%mod*500000004ll%mod*(2*sum(n/k)-1)%mod) %= mod; } cout << ans << endl; return 0;}
bzoj1044: [HAOI2008]木棍分割
水题..然而神奇的是sdp那个数组如果取模速度会慢4倍左右而被肉眼可见卡常数…
哪位松爷的忠实粉丝来解释下..
#include <bits/stdc++.h>using namespace std;const int MAXN = 50005;int l[MAXN], n, m;long long dp[MAXN][2], s[MAXN], sdp[MAXN];int pos[MAXN];inline int read(){ int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}bool judge(int k){ int tm = m, len = 0; for (register int i = 1; i <= n; i++) { if (len+l[i] > k) len = l[i], tm--; else len = len+l[i]; if (len > k) return 0; if (tm < 0) return 0; } return 1;}int main(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { l[i] = read(), s[i] = s[i-1]+l[i]; } int l = 0, r = 50000000, mid, ans; while (l <= r) { mid = (l+r)>>1; if (judge(mid)) r = mid-1; else l = mid+1; } ans = r+1; for (register int i = 0; i <= n; i++) dp[i][0] = (s[i] <= ans); int now = 1, pre = 0; int cnt = (s[n] <= ans); register int k = 1; for (register int i = 0; i <= n; i++) { while (s[i]-s[k] > ans) k++; pos[i] = k; } for (int j = 1; j <= m; j++) { for (register int k = 0; k <= n; k++) sdp[k+1] = sdp[k]+dp[k][pre]; for (register int i = 0; i <= n; i++) dp[i][now] = (sdp[i]-sdp[pos[i]])%10007; (cnt += dp[n][now]) %= 10007; swap(now, pre); } cout << ans << " " << (cnt+10007)%10007 << endl; return 0;}
bzoj1923: [Sdoi2010]外星千足虫
被输入整惨了…
为什么bitset的输入逻辑这么诡异…
#include <bits/stdc++.h>using namespace std;bitset<1005> g[2005], y, x;int n, m, b;int lab[2005];int readbit(){ int c = 0; do c = getchar(); while (!isdigit(c)); return c-'0';}void gauss(){ int k = 0; for (int i = 0; i < m; i++) { if (g[i][i] == 0) { for (register int j = i+1; j < m; j++) if (g[j][i]) { swap(g[i], g[j]), swap(lab[i], lab[j]); int t = y[i]; y[i] = y[j], y[j] = t; break; } if (g[i][i] == 0) continue; } k = max(k, lab[i]); for (register int j = 0; j < m; j++) if (j != i && g[j][i]) { g[j] = (g[j]^g[i]); y[j] = (y[j]^y[i]); } } for (int i = n-1; i >= 0; i--) if (!g[i][i]) { puts("Cannot Determine"); return; } printf("%d\n", k+1); for (int i = 0; i < n; i++) if (y[i]) puts("?y7M#"); else puts("Earth");}int main(){ scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { lab[i] = i; for (register int j = 0; j < n; j++) g[i][j] = readbit(); y[i] = readbit(); } gauss(); return 0;}
bzoj4516: [Sdoi2016]生成魔咒
SAM秒掉了..小清新数据结构题..
这才是省选该有的画风吧QwQ
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;map<int, int> chl[MAXN*2];int fa[MAXN*2], maxl[MAXN*2];int top = 1, root = 1, last = 1;long long ans = 0;int n, x;void push(int x){ int p = last, np = ++top; maxl[np] = maxl[p]+1; while (p && !chl[p][x]) chl[p][x] = np, p = fa[p]; if (!p) fa[np] = root, ans += maxl[np]-maxl[fa[np]]; else { int q = chl[p][x]; if (maxl[q] == maxl[p]+1) fa[np] = q, ans += maxl[np]-maxl[fa[np]]; else { int nq = ++top; maxl[nq] = maxl[p]+1; chl[nq] = chl[q]; ans -= maxl[q]-maxl[fa[q]]; fa[nq] = fa[q], fa[q] = nq, fa[np] = nq; ans += maxl[nq]-maxl[fa[nq]], ans += maxl[q]-maxl[fa[q]], ans += maxl[np]-maxl[fa[np]]; while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p]; } } last = np;}int main(){ scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &x), push(x); printf("%d\n", ans); } return 0;}
bzoj2431: [HAOI2009]逆序对数列
刷水有益健康。
#include <bits/stdc++.h>using namespace std;const int MAXN = 1005, MAXK = 1005;int n, k;int dp[2][1005], s[1005];int main(){ scanf("%d%d", &n, &k); dp[0][0] = 1; for (int i = 1; i <= n; i++) { for (register int j = 0; j <= k; j++) s[j+1] = (s[j]+dp[0][j])%10000; for (register int j = 0; j <= k; j++) { int l = max(0, j-(i-1)), r = j; dp[1][j] = (s[r+1]-s[l])%10000; } swap(dp[0], dp[1]); } cout << (dp[0][k]+10000)%10000 << endl; return 0;}
bzoj4755: [Jsoi2016]扭动的回文串
核心是第三个操作的重要结论:A、B两串扭曲成回文串时,若回文中心在A中,则该串必然包含以其为中心最长的回文子串。
证明:回文中心是缝隙的通过添加无用字符可以转化为回文中心是字符,设回文中心为
设:
由于
所以
另一方面还需要证明如果一个回文串被方案真包含那么它一定不是最长回文串,由于太显然就不证了。
其实画个图就都显然了啊233
之后这题就是代码题了,需要细致讨论每一种情况。由于懒各种复制,代码冗长不可读,1A真是侥幸…
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;typedef unsigned long long ull;char A[MAXN], B[MAXN];ull hashA[MAXN], hashB[MAXN], invA[MAXN], invB[MAXN], power[MAXN];int bas = 31, n;int pA[MAXN][2], pB[MAXN][2];inline unsigned long long hash_val(ull hst[], int l, int r){ return hst[r]-power[r-l+1]*hst[l-1]; }inline unsigned long long hash_inv(ull hst[], int l, int r){ return hst[l]-power[r+1-l]*hst[r+1]; }int maxlen(ull str[], ull inv[]){ int ans = 0; for (int i = 1; i <= n; i++) { int l = 0, r = min(i-1, n-i), mid; while (l <= r) { mid = (l+r)>>1; if (hash_val(str, i-mid, i) == hash_inv(inv, i, i+mid)) l = mid+1; else r = mid-1; } ans = max(ans, 2*(l-1)+1); } for (int i = 1; i < n; i++) { int l = 1, r = min(i, n-i), mid; if (hash_val(str, i, i) != hash_val(str, i+1, i+1)) continue; while (l <= r) { mid = (l+r)>>1; if (hash_val(str, i-mid+1, i) == hash_inv(inv, i+1, i+mid)) l = mid+1; else r = mid-1; } ans = max(ans, 2*(l-1)); } return ans;}int maxl(ull iA[], int i, ull B[], int j){ int l = 1, r = min(i, n-j+1), mid; if (hash_inv(iA, i, i) != hash_val(B, j, j)) return 0; while (l <= r) { mid = (l+r)>>1; if (hash_inv(iA, i-mid+1, i) == hash_val(B, j, j+mid-1)) l = mid+1; else r = mid-1; } return l-1;}int maxdouble(ull A[], ull iA[], ull B[]){ int ans = 0; for (int i = 1; i <= n; i++) { int l = 0, r = min(i-1, n-i), mid; while (l <= r) { mid = (l+r)>>1; if (hash_val(A, i-mid, i) == hash_inv(iA, i, i+mid)) l = mid+1; else r = mid-1; } int len = l-1; ans = max(ans, 2*len+1+2*maxl(iA, i-len-1, B, i+len)); } for (int i = 1; i <= n; i++) { int l = 1, r = min(i, n-i), mid; if (hash_val(A, i, i) != hash_val(A, i+1, i+1)) { ans = max(ans, 2*maxl(iA, i, B, i)); continue; } while (l <= r) { mid = (l+r)>>1; if (hash_val(A, i-mid+1, i) == hash_inv(iA, i+1, i+mid)) l = mid+1; else r = mid-1; } int len = l-1; ans = max(ans, 2*len+2*maxl(iA, i-len, B, i+len)); } return ans;}int maxdouble2(ull A[], ull iA[], ull iB[]){ int ans = 0; for (int i = 1; i <= n; i++) { int l = 0, r = min(i-1, n-i), mid; while (l <= r) { mid = (l+r)>>1; if (hash_val(A, i-mid, i) == hash_inv(iA, i, i+mid)) l = mid+1; else r = mid-1; } int len = l-1; //todo ans = max(ans, 2*len+1+2*maxl(iB, i-len, A, i+len+1)); } for (int i = 1; i <= n; i++) { int l = 1, r = min(i, n-i), mid; if (hash_val(A, i, i) != hash_val(A, i+1, i+1)) { ans = max(ans, 2*maxl(iB, i, A, i)); continue; } while (l <= r) { mid = (l+r)>>1; if (hash_val(A, i-mid+1, i) == hash_inv(iA, i+1, i+mid)) l = mid+1; else r = mid-1; } int len = l-1; ans = max(ans, 2*len+2*maxl(iB, i-len+1, A, i+len+1)); } return ans;}int main(){ scanf("%d", &n); scanf("%s", A+1); scanf("%s", B+1); power[0] = 1; for (int i = 1; i <= n; i++) power[i] = power[i-1]*bas; for (int i = 1; i <= n; i++) { hashA[i] = hashA[i-1]*bas+A[i]-'A'+1; hashB[i] = hashB[i-1]*bas+B[i]-'A'+1; } for (int i = n; i >= 1; i--) { invA[i] = invA[i+1]*bas+A[i]-'A'+1; invB[i] = invB[i+1]*bas+B[i]-'A'+1; } int ans = max(maxlen(hashA, invA), maxlen(hashB, invB)); ans = max(ans, maxdouble(hashA, invA, hashB)); ans = max(ans, maxdouble2(hashB, invB, invA)); cout << ans << endl; return 0;}
bzoj3876: [Ahoi2014]支线剧情
上下界费用流建模还是比较显然的..
然而会被卡常数..于是抄了zkw费用流过了..
有时间研究一下。
spfa费用流(TLE):
#include <bits/stdc++.h>using namespace std;const int MAXN = 305, MAXM = 100005, inf = 233333333;struct node { int to, next, flow, cost, neg;} edge[MAXM];int head[MAXN], top = 0;inline void push(int i, int j, int f, int c){ ++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top; ++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;}const int S = 301, T = 302, SS = 303, ST = 304;int addin = 0;inline void push_lim(int i, int j, int cost, int minc){ push(SS, j, minc, cost), push(i, ST, minc, 0); addin += minc; push(i, j, inf, cost);}queue<int> que;int dis[MAXN], vis[MAXN], pre[MAXN], pre_edge[MAXN];bool spfa(int &cost, int &maxf){ memset(dis, 127/3, sizeof dis), memset(vis, 0, sizeof vis); vis[SS] = 1, dis[SS] = 0, que.push(SS); while (!que.empty()) { int nd = que.front(); vis[nd] = 0, que.pop(); for (register int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to, f = edge[i].flow, c = edge[i].cost; if (!f) continue; if (dis[to] > dis[nd]+c) { dis[to] = dis[nd]+c; pre[to] = nd, pre_edge[to] = i; if (!vis[to]) vis[to] = 1, que.push(to); } } } if (dis[ST] >= inf) return 0; int mx = inf; for (register int i = ST; i != SS; i = pre[i]) mx = min(mx, edge[pre_edge[i]].flow); for (register int i = ST; i != SS; i = pre[i]) edge[pre_edge[i]].flow -= mx, edge[edge[pre_edge[i]].neg].flow += mx; maxf += mx, cost += mx*dis[ST]; // cout <<endl<< mx << " " << mx*dis[ST] << "--\n"; return 1;}int mcf(int &cost){ cost = 0; int ans = 0; while (spfa(cost, ans)); return ans;}int n, k, u, t;int main(){ scanf("%d", &n); push(T, S, inf, 0), push(S, 1, inf, 0); for (int i = 1; i <= n; i++) { scanf("%d", &k); push(i, T, inf, 0); for (register int j = 1; j <= k; j++) { scanf("%d%d", &u, &t); push_lim(i, u, t, 1); } } int f = 0, c = 0; f = mcf(c); cout << c << endl; return 0;}
zkw费用流(AC):
#include <bits/stdc++.h>using namespace std;const int MAXN = 305, MAXM = 100005, inf = 233333333;struct node { int to, next, flow, cost, neg;} edge[MAXM];int head[MAXN], top = 0;inline void push(int i, int j, int f, int c){ ++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top; ++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;}const int S = 301, T = 302, SS = 303, ST = 304;int addin = 0;inline void push_lim(int i, int j, int cost, int minc){ push(SS, j, minc, cost), push(i, ST, minc, 0); addin += minc; push(i, j, inf, cost);}bool vis[MAXN];int cost = 0, pi1 = 0;int arg(int nd, int maxf = inf){ if (nd == ST) return cost += maxf*pi1, maxf; vis[nd] = 1; // cout << nd << endl; int ans = 0, t; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to, c = edge[i].cost, f = edge[i].flow; if (!f || vis[to] || c) continue; t = arg(to, min(maxf, f)); ans += t, maxf -= t, edge[i].flow -= t, edge[edge[i].neg].flow += t; if (!maxf) break; } return ans;}bool modlabel(){ int d = inf; for (int i = 1; i <= MAXN-1; i++) if (vis[i]) for (int j = head[i]; j; j = edge[j].next) if (edge[j].flow && !vis[edge[j].to]) d = min(d, edge[j].cost); if (d == inf) return 0; for (int i = 1; i <= MAXN-1; i++) if (vis[i]) for (int j = head[i]; j; j = edge[j].next) edge[j].cost -= d, edge[edge[j].neg].cost += d; pi1 += d; return 1;}int n, k, u, t;void mcf(){ do do memset(vis, 0, sizeof vis); while (arg(SS)); while (modlabel());}int main(){ scanf("%d", &n); push(T, S, inf, 0), push(S, 1, inf, 0); for (int i = 1; i <= n; i++) { scanf("%d", &k); push(i, T, inf, 0); for (register int j = 1; j <= k; j++) { scanf("%d%d", &u, &t); push_lim(i, u, t, 1); } } mcf(); cout << cost << endl; return 0;}
bzoj2762: [JLOI2011]不等式组
分类讨论题..
#include <bits/stdc++.h>using namespace std;int lp = -2e6, rp = 2e6;void calc(int a, int b, int c, int &l, int &r){ c = c-b; // cout << a << " " << b << " " << c << endl; if (a > 0) { if (c > 0) l = c/a+1, r = rp; else if (c < 0) l = c/a+(c%a==0), r = rp; else l = 1, r = rp; } else if (a < 0) { if (c > 0) l = lp, r = c/a-1; else if (c < 0) l = lp, r = c/a-(c%a==0); else l = lp, r = -1; } else { if (c < 0) l = lp, r = rp; else l = 1, r = 0; } if (l < lp) l = lp; if (r > rp) r = rp;}int c[4000010], n = 4e6+2;inline int lowbit(int i) { return i&(-i); }int sum(int i){ i += 2e6+1; int ans = 0; while (i) ans += c[i], i -= lowbit(i); return ans;}void add(int pos, int dt){ for (int i = pos; i <= n; i += lowbit(i)) c[i] += dt; }void modify(int l, int r, int dt){ // printf("[%d,%d] -- %d\n", l, r, dt); if (l > r) return; l += 2e6+1, r += 2e6+1; add(l, dt), add(r+1, -dt);}int a[100005], b[100005], d[100005], dd[100005], top = 0, n2;char str[10];int main(){ scanf("%d", &n2); for (int i = 1; i <= n2; i++) { scanf("%s", str); if (str[0] == 'A') { ++top, scanf("%d%d%d", &a[top], &b[top], &d[top]); int l, r; calc(a[top], b[top], d[top], l, r); modify(l, r, 1); } else if (str[0] == 'D') { int u; scanf("%d", &u); if (dd[u] == 1) continue; dd[u] = 1; int l, r; calc(a[u], b[u], d[u], l, r); modify(l, r, -1); } else { int k; scanf("%d", &k); printf("%d\n", sum(k)); } } return 0;}
bzoj3879: SvT
貌似也是套路题..建好SA后把相隔两点间区间最值扔进单调栈.
模块调试大法好.
#include <bits/stdc++.h>using namespace std;const int MAXN = 500010;struct SA { struct ele { int k[2]; int id; ele(){k[0] = k[1] = 0; } ele(int i, int x, int y) {id = i, k[0] = x, k[1] = y; } } RE[MAXN], RT[MAXN]; int sa[MAXN], rank[MAXN], height[MAXN], sum[MAXN], A[MAXN], n; void radix_sort() { for (int y = 1; y >= 0; y--) { memset(sum, 0, sizeof sum); for (int i = 1; i <= n; i++) sum[RE[i].k[y]]++; for (int i = 1; i < MAXN; i++) sum[i] += sum[i-1]; for (int i = n; i >= 1; i--) RT[sum[RE[i].k[y]]--] = RE[i]; for (int i = 1; i <= n; i++) RE[i] = RT[i]; } for (int i = 1; i <= n; i++) { rank[RE[i].id] = rank[RE[i-1].id]; if (RE[i].k[0] != RE[i-1].k[0] || RE[i].k[1] != RE[i-1].k[1]) rank[RE[i].id]++; } } void calc_sa() { for (int i = 1; i <= n; i++) RE[i] = ele(i, A[i], 0); radix_sort(); for (int k = 1; k < n; k <<= 1) { for (int j = 1; j <= n; j++) RE[j] = ele(j, rank[j], j+k<=n?rank[j+k]:0); radix_sort(); } for (int i = 1; i <= n; i++) sa[rank[i]] = i; } void calc_height() { int h = 0; for (int i = 1; i <= n; i++) { if (rank[i] == 1) h = 0; else { int k = sa[rank[i]-1]; if (--h < 0) h = 0; while (A[k+h] == A[i+h]) h++; } height[rank[i]] = h; } }} SA;int m;inline int read() { int a = 0, c; do c = getchar(); while(!isdigit(c)); while (isdigit(c)) { a = a*10+c-'0'; c = getchar(); } return a;}int pos[MAXN];int f[MAXN][21];inline int min_val(int l, int r){ if (l > r) return 0; int k = int(log2(r-l+1)+0.001); return min(f[l][k], f[r-(1<<k)+1][k]);}const long long mod = 23333333333333333ll;struct slv { struct ele { long long dat, len; } stk[MAXN]; int top; long long ans, sum; void clear() { top = ans = sum = 0; } void push(long long x) { if (!top) { stk[++top] = (ele){x, 1}, (sum += x) %= mod, (ans += sum) %= mod; return; } ele k = (ele){x, 1}; while (stk[top].dat > x) k.len += stk[top].len, (sum -= stk[top].dat*stk[top].len) %= mod, top--; stk[++top] = k, (sum += stk[top].dat*stk[top].len) %= mod, (ans += sum) %= mod; }} solver;int main(){ scanf("%d%d\n", &SA.n, &m); for (int i = 1; i <= SA.n; i++) scanf("%c", &SA.A[i]), SA.A[i] -= 'a'-1; SA.calc_sa(); SA.calc_height(); for (int i = 1; i <= SA.n; i++) f[i][0] = SA.height[i]; for (int j = 1; j <= 20; j++) for (int i = 1; i <= SA.n; i++) { f[i][j] = f[i][j-1]; if (i+(1<<(j-1)) <= SA.n) f[i][j] = min(f[i][j], f[i+(1<<(j-1))][j-1]); } for (int i = 1; i <= m; i++) { int t; t = read(); solver.clear(); for (int j = 1; j <= t; j++) pos[j] = SA.rank[read()]; sort(pos+1, pos+t+1); t = unique(pos+1, pos+t+1)-pos-1; for (int j = 1; j < t; j++) pos[j] = min_val(pos[j]+1, pos[j+1]); for (int j = 1; j < t; j++) solver.push(pos[j]); printf("%lld\n", solver.ans); } return 0;}
bzoj4753: [Jsoi2016]最佳团体
分数规划.先二分答案,然后用树形dp判断。
这个dp比较神奇,是按照dfs序dp的。
然而被卡精度…
WA:
#include <bits/stdc++.h>using namespace std;const int MAXN = 3005;struct node { int to, next;} edge[MAXN*2];int head[MAXN], top = 0;inline void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }int n, k;int s[MAXN], p[MAXN], r[MAXN];int dfn[MAXN], dfn_top = 0, siz[MAXN];long double dp[MAXN][MAXN], dat[MAXN];void dfs(int nd){ siz[nd] = 1, dfn[++dfn_top] = nd; for (int i = head[nd]; i; i = edge[i].next) dfs(edge[i].to), siz[nd] += siz[edge[i].to];}long double do_dp(){ for (int i = 0; i <= n+2; i++) for (int j = 0; j <= k+1; j++) dp[i][j] = -1e20; dp[1][0] = 0; for (int i = 1; i <= n+1; i++) { for (int j = 0; j <= min(k+1, i-1); j++) { if (dp[i][j] == -1e20) continue; dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j] + dat[dfn[i]]); dp[i+siz[dfn[i]]][j] = max(dp[i+siz[dfn[i]]][j], dp[i][j]); // cout << dp[i][j] << " "; } // puts(""); } return dp[n+2][k+1];}const long double eps = 1e-5;bool judge(long double md){ for (int i = 1; i <= n; i++) dat[i] = p[i]-s[i]*md; do_dp(); return dp[n+2][k+1] >= 0.0;}int main(){ scanf("%d%d", &k, &n); for (int i = 1; i <= n; i++) scanf("%d%d%d", &s[i], &p[i], &r[i]); for (int i = 1; i <= n; i++) push(r[i]?r[i]:n+1, i); dfs(n+1); // for (int i = 1; i <= n+1; i++) // cout << dfn[i] << " "; // puts(""); long double l = 0, r = 1e4, mid; while (r-l >= eps) { mid = (l+r)/2; // cout << mid << endl; if (judge(mid)) l = mid; else r = mid; } printf("%.3lf\n", mid); return 0;}
bzoj4827: [Hnoi2017]礼物
首先用一眼法知道
然后就三分+FFT了..擦边AC..
【233ms的神犇是怎么做的??】
#include <bits/stdc++.h>using namespace std;const int MAXN = 400005;typedef complex<double> Complex;int rev[MAXN];Complex x[MAXN], y[MAXN], z[MAXN], A[MAXN];const double PI = acos(-1);void FFT(Complex a[], int n, int flag){ rev[0] = 0; int lgn = int(log2(n)+0.001); for (int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(lgn-1)); for (int i = 0; i < n; i++) A[rev[i]] = a[i]; for (int k = 2; k <= n; k <<= 1) { Complex dw = Complex(cos(2*PI/k), flag*sin(2*PI/k)), u, v; for (register int i = 0; i < n; i += k) { Complex w = Complex(1, 0); for (register int j = 0; j < k>>1; j++) { u = A[i+j], v = w*A[i+j+(k>>1)]; A[i+j] = u+v, A[i+j+(k>>1)] = u-v; w *= dw; } } } for (int i = 0; i < n; i++) if (flag == 1) a[i] = A[i]; else a[i] = A[i]/Complex(n, 0);}int n, m;int xi[MAXN], yi[MAXN];long long zi[MAXN];long long ans = INT_MAX, cnt = 0;int w = 1;long long solve(int i){ cnt = 0; for (int j = 0; j < n; j++) x[j] = Complex(xi[j]+i, 0), y[n-j-1] = Complex(yi[j], 0), cnt += (xi[j]+i)*(xi[j]+i)+yi[j]*yi[j]; for (int j = n; j < w; j++) x[j] = y[j] = Complex(0, 0); FFT(x, w, 1), FFT(y, w, 1); for (int j = 0; j < w; j++) z[j] = x[j]*y[j]; FFT(z, w, -1), FFT(x, w, -1); for (int j = 0; j < w; j++) zi[j] = (long long)(z[j].real()+0.001); long long d = INT_MAX; for (int j = 0; j < n; j++) d = min(d, cnt-2*(zi[j]+zi[n+j])); return d;}int main(){ scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) scanf("%d", &xi[i]); for (int i = 0; i < n; i++) scanf("%d", &yi[i]); for (; w <= 2*n; w <<= 1); int a = -m, d = m, b, c; while (d-a >= 3) { b = a+(d-a)/3, c = a+(d-a)/3*2; if (solve(b) < solve(c)) d = c; else a = b; } for (int i = a; i <= d; i++) ans = min(ans, solve(i)); cout << ans << endl; return 0;}
- bzoj刷题记录5.6-5.10
- BZOJ刷题记录
- BZOJ刷题记录(2014)
- BZOJ 刷题记录 PART 1
- BZOJ 刷题记录 PART 2
- BZOJ 刷题记录 PART 3
- BZOJ 刷题记录 PART 4
- BZOJ 刷题记录 PART 5
- BZOJ 刷题记录 PART 6
- bzoj刷题记录2017.4.2-4.4
- bzoj刷题记录:4.5-4.9
- bzoj刷题记录4.10-4.14
- bzoj刷题记录4.15-4.16
- bzoj刷题记录4.17-4.21
- bzoj刷题记录4.25-5.1
- bzoj刷题记录5.11-5.15
- BZOJ刷题记录(施工到AFO)
- OI刷题记录
- JAVA assert(断言)
- 欢迎使用CSDN-markdown编辑器
- Linux下的文件描述符与文件指针
- 解决微信小程序使用switchTab跳转后页面不刷新的问题
- QT笔记(4)——Qt的lineEdit添加鼠标点击事件
- bzoj刷题记录5.6-5.10
- 怎样读书和选书
- 第十四届五一数学建模竞赛赛题
- 什么是光栅化
- Leetcode学习(20)—— Longest Uncommon Subsequence I
- 按钮背景代码中设置和倒计时的使用
- 2017广东省红帽杯网络安全攻防大赛writeup
- 装饰者模式
- video.js 视频播放插件及常见问题