[关闭]
@ljt12138 2017-05-01T22:34:58.000000Z 字数 17151 阅读 986

bzoj刷题记录4.25-5.1

1823: [JSOI2010]满汉全席

2-SAT裸题:ab=¬ab=¬ba,然后tarjan就行了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 505, MAXM = 10005;
  4. struct node {
  5. int to, next;
  6. } edge[MAXM];
  7. int head[MAXN], top = 0;
  8. void push(int i, int j)
  9. { edge[++top] = (node){j, head[i]}, head[i] = top; }
  10. int n, m;
  11. int neg(int nd)
  12. { return nd>n?nd-n:nd+n; }
  13. int T;
  14. int dfn[MAXN], low[MAXN], stk[MAXN], instk[MAXN], stop = 0, dftop = 0;
  15. bool tarjan(int nd)
  16. {
  17. dfn[nd] = low[nd] = ++dftop;
  18. instk[nd] = 1, stk[++stop] = nd;
  19. for (int i = head[nd]; i; i = edge[i].next) {
  20. int to = edge[i].to;
  21. if (!dfn[to]) {
  22. if (!tarjan(to)) return 0;
  23. low[nd] = min(low[nd], low[to]);
  24. }
  25. else if (instk[to]) low[nd] = min(low[nd], dfn[to]);
  26. }
  27. if (dfn[nd] == low[nd]) {
  28. int now = 0;
  29. do {
  30. now = stk[stop--], instk[now] = 0;
  31. if (now == neg(nd)) return 0;
  32. } while (now != nd);
  33. }
  34. return 1;
  35. }
  36. bool fail()
  37. {
  38. memset(dfn, 0, sizeof dfn);
  39. for (int i = 1; i <= n*2; i++)
  40. if (!dfn[i])
  41. if (!tarjan(i)) return 1;
  42. return 0;
  43. }
  44. int main()
  45. {
  46. scanf("%d", &T);
  47. while (T--) {
  48. top = 0, memset(head, 0, sizeof head);
  49. dftop = 0, stop = 0;
  50. memset(instk, 0, sizeof instk);
  51. scanf("%d%d", &n, &m);
  52. for (int i = 1; i <= m; i++) {
  53. char t1, t2; int n1, n2;
  54. scanf("\n%c%d %c%d", &t1, &n1, &t2, &n2);
  55. if (t1 == 'm') n1 = neg(n1);
  56. if (t2 == 'm') n2 = neg(n2);
  57. push(neg(n1), n2), push(neg(n2), n1);
  58. }
  59. if (fail()) puts("BAD");
  60. else puts("GOOD");
  61. }
  62. return 0;
  63. }

bzoj2756: [SCOI2012]奇怪的游戏

网络流。http://hzwer.com/5992.html

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 50*51, MAXM = 50*50*50;
  4. struct node {
  5. int to, next;
  6. long long flow;
  7. int neg;
  8. } edge[MAXM];
  9. int head[MAXN], top = 0;
  10. void push(int i, int j, long long f)
  11. {
  12. ++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;
  13. ++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;
  14. }
  15. int S = 2531, T = 2532;
  16. long long inf = 233333333333ll;
  17. int vis[MAXN], bfstime = 0, lev[MAXN];
  18. queue<int> que;
  19. bool bfs()
  20. {
  21. vis[S] = ++bfstime, lev[S] = 0, que.push(S);
  22. while (!que.empty()) {
  23. int f = que.front(); que.pop();
  24. for (int i = head[f]; i; i = edge[i].next) {
  25. int to = edge[i].to;
  26. long long fl = edge[i].flow;
  27. if (!fl || vis[to] == bfstime) continue;
  28. lev[to] = lev[f] + 1, vis[to] = bfstime, que.push(to);
  29. }
  30. }
  31. return vis[T] == bfstime;
  32. }
  33. long long dfs(int nd, long long mf = inf)
  34. {
  35. if (nd == T || !mf) return mf;
  36. long long t, ans = 0;
  37. for (int i = head[nd]; i; i = edge[i].next) {
  38. int to = edge[i].to; long long f = edge[i].flow;
  39. if (!f || lev[to] != lev[nd]+1) continue;
  40. t = dfs(to, min(mf, f));
  41. ans += t, mf -= t;
  42. edge[i].flow -= t, edge[edge[i].neg].flow += t;
  43. }
  44. if (mf) lev[nd] = -1;
  45. return ans;
  46. }
  47. long long dinic()
  48. {
  49. long long ans = 0;
  50. while (bfs()) ans += dfs(S);
  51. return ans;
  52. }
  53. long long chess_board[55][55];
  54. int n, m, Tp;
  55. long long x[2] = {0,0}, sx[2] = {0,0};
  56. inline int number(int i, int j)
  57. { return (i-1)*m+j;}
  58. int dx[] = {0,1,0,-1}, dy[] = {1,0,-1,0};
  59. bool judge(long long z)
  60. {
  61. bfstime = 0, top = 0, memset(head, 0, sizeof head);
  62. for (int i = 1; i <= n; i++)
  63. for (int j = 1; j <= m; j++) {
  64. if (z-chess_board[i][j] < 0) return 0;
  65. if ((i+j)&1) push(S, number(i, j), z-chess_board[i][j]);
  66. else push(number(i, j), T, z-chess_board[i][j]);
  67. }
  68. for (int i = 1; i <= n; i++)
  69. for (int j = 1; j <= m; j++) {
  70. if (!((i+j)&1)) continue;
  71. for (int k = 0; k < 4; k++) {
  72. int nx = i+dx[k], ny = j+dy[k];
  73. if (nx >= 1 && nx <= n && ny >= 1 && ny <= m)
  74. push(number(i, j), number(nx, ny), inf);
  75. }
  76. }
  77. long long fl = dinic();
  78. return fl == z*x[0]-sx[0];
  79. }
  80. int main()
  81. {
  82. scanf("%d", &Tp);
  83. while (Tp--) {
  84. scanf("%d%d", &n, &m);
  85. x[0] = x[1] = sx[0] = sx[1] = 0;
  86. for (int i = 1; i <= n; i++)
  87. for (int j = 1; j <= m; j++) {
  88. scanf("%lld", &chess_board[i][j]);
  89. x[(i+j)&1]++, sx[(i+j)&1] += chess_board[i][j];
  90. }
  91. if (x[0] != x[1]) {
  92. if ((sx[0]-sx[1])%(x[0]-x[1]) != 0) puts("-1");
  93. else {
  94. long long val = (sx[0]-sx[1])/(x[0]-x[1]);
  95. if (judge(val)) printf("%lld\n", val*x[0]-sx[0]);
  96. else puts("-1");
  97. }
  98. } else {
  99. if (sx[0] != sx[1]) puts("-1");
  100. else {
  101. long long l = 0, r = inf, mid;
  102. while (l <= r) {
  103. mid = (l+r)>>1;
  104. if (!judge(mid)) l = mid+1;
  105. else r = mid-1;
  106. }
  107. printf("%lld\n", l*x[0]-sx[0]);
  108. }
  109. }
  110. }
  111. return 0;
  112. }

bzoj2809: [Apio2012]dispatching

第一反应是可并堆.
然而可并堆的空间会不会爆炸呢..后来发现是不会炸的..每个元素至多只入一次堆,删除一次,总复杂度还是O(nlgn)的。

结果写了可持久化权值线段树..离散化,找出dfn序用可持久化线段树维护区间内有值的点数和总和,然后二分就好,复杂度也是O(nlgn).

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005, lgn = 20;
  4. int lc[MAXN*20], rc[MAXN*20], l[MAXN*20];
  5. int r[MAXN*20], top = 0;
  6. long long dat[MAXN*20], sum[MAXN*20], siz[MAXN*20], dx[MAXN];
  7. int root[MAXN];
  8. int n;
  9. long long m;
  10. inline void update(int nd)
  11. {
  12. sum[nd] = sum[lc[nd]] + sum[rc[nd]] + dat[nd];
  13. if (l[nd] == r[nd]) siz[nd] = dat[nd] != 0;
  14. else siz[nd] = siz[lc[nd]] + siz[rc[nd]];
  15. }
  16. void build(int &nd, int opl, int opr)
  17. {
  18. nd = ++top, l[nd] = opl, r[nd] = opr;
  19. if (opl < opr)
  20. build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
  21. }
  22. void push(int prev, int &nd, int pos)
  23. {
  24. nd = ++top, l[nd] = l[prev], r[nd] = r[prev];
  25. if (l[prev] == r[prev]) dat[nd] = dx[pos]/(n+1), update(nd);
  26. else {
  27. int mid = (l[prev]+r[prev])/2;
  28. if (pos <= mid) push(lc[prev], lc[nd], pos), rc[nd] = rc[prev], update(nd);
  29. else push(rc[prev], rc[nd], pos), lc[nd] = lc[prev], update(nd);
  30. }
  31. }
  32. int answer(int lpos, int rpos, long long sm)
  33. {
  34. lpos--;
  35. int i = 1, j = n, mid, lr = root[lpos], rr = root[rpos];
  36. int ans = 0;
  37. while (i < j) {
  38. mid = (i+j)>>1;
  39. int lp = lc[lr], rp = lc[rr];
  40. if (sum[rp]-sum[lp] >= sm) lr = lp, rr = rp, j = mid;
  41. else sm -= sum[rp]-sum[lp], ans += siz[rp]-siz[lp], lr = rc[lr], rr = rc[rr], i = mid+1;
  42. }
  43. if (sm >= sum[rr]-sum[lr]) ans += siz[rr]-siz[lr];
  44. return ans;
  45. }
  46. struct node {
  47. int to, next;
  48. } edge[MAXN];
  49. int head[MAXN], tp = 0;
  50. void push(int i, int j)
  51. { edge[++tp] = (node){j, head[i]}, head[i] = tp; }
  52. int fa[MAXN], in[MAXN], out[MAXN], dfn = 0;
  53. long long money[MAXN], leader[MAXN];
  54. int dx_num(long long num, int i)
  55. { return lower_bound(dx+1, dx+n+1, num*(n+1)+i)-dx; }
  56. void dx_init()
  57. {
  58. for (int i = 1; i <= n; i++) dx[i] = money[i]*(n+1)+i;
  59. sort(dx+1, dx+n+1);
  60. }
  61. void dfs(int nd)
  62. {
  63. in[nd] = ++dfn;
  64. push(root[dfn-1], root[dfn], dx_num(money[nd], nd));
  65. for (int i = head[nd]; i; i = edge[i].next)
  66. dfs(edge[i].to);
  67. out[nd] = dfn;
  68. }
  69. long long query(int nd)
  70. { return leader[nd]*answer(in[nd], out[nd], m); }
  71. int main()
  72. {
  73. scanf("%d%lld", &n, &m);
  74. int master = 0;
  75. for (int i = 1; i <= n; i++)
  76. scanf("%d%lld%lld", &fa[i], &money[i], &leader[i]);
  77. build(root[0], 1, n);
  78. dx_init();
  79. for (int i = 1; i <= n; i++) {
  80. if (!fa[i]) master = i;
  81. else push(fa[i], i);
  82. }
  83. dfs(master);
  84. long long ans = 0;
  85. for (int i = 1; i <= n; i++)
  86. ans = max(ans, query(i));
  87. printf("%lld\n", ans);
  88. return 0;
  89. }

bzoj3206: [Apio2013]道路费用

没过...
用国内数据和hzwer及几分其他std拍都拍过了,然而bzoj上还是WA...奇特的是我们拿那份Te数据都WA一个点且结果一样。

然而hzwer代码bzoj可过而这份不可过...

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. const int MAXN = 100005, MAXM = 300105;
  7. int fa[MAXN];
  8. inline int findf(int nd)
  9. { return fa[nd]?fa[nd]=findf(fa[nd]):nd; }
  10. int gp[MAXN];
  11. long long siz[MAXN];
  12. inline int findgp(int nd)
  13. { return gp[nd]?gp[nd]=findgp(gp[nd]):nd; }
  14. void link(int i, int j)
  15. {
  16. int a = findgp(i), b = findgp(j);
  17. if (a != b)
  18. gp[a] = b, siz[b] += siz[a];
  19. }
  20. struct edge {
  21. int x, y;
  22. long long c;
  23. int on_eg;
  24. edge(){ on_eg = 1; }
  25. friend bool operator < (const edge &a, const edge &b)
  26. { return a.c < b.c; }
  27. } edge[MAXM], knew[105], inp[MAXM];
  28. int n, m, k;
  29. const long long INF = 1234567891011ll;
  30. struct node {
  31. int to, next;
  32. long long dis;
  33. } graph[105];
  34. int head[MAXN], top = 0;
  35. int stk[50], t = 0;
  36. inline void push(int i, int j, long long dis)
  37. { //printf("%d--%lld-->%d\n", i, dis, j);
  38. graph[++top] = (node){j, head[i], dis}, head[i] = top; }
  39. void mst(int eg, int flag = 0, int p = 0)
  40. {
  41. // cout << eg << endl;
  42. sort(edge+1, edge+eg+1);
  43. if (!p) memset(fa, 0, sizeof fa);
  44. else {
  45. for (int i = 1; i <= t; i++)
  46. fa[stk[i]] = 0;
  47. }
  48. for (int i = 1; i <= eg; i++) {
  49. int a = findf(findgp(edge[i].x)), b = findf(findgp(edge[i].y));
  50. if (a != b) {
  51. fa[a] = b;
  52. // printf("On MST --- %d, %d, %lld\n", a, b, edge[i].c);
  53. if (flag) {
  54. push(findgp(edge[i].x), findgp(edge[i].y), edge[i].c);
  55. push(findgp(edge[i].y), findgp(edge[i].x), edge[i].c);
  56. }
  57. } else {
  58. if (!p)edge[i].c = INF;
  59. edge[i].on_eg = 0;
  60. }
  61. }
  62. }
  63. void cut1()
  64. {
  65. memcpy(edge, inp, sizeof inp);
  66. int tp = m;
  67. for (int i = 1; i <= k; i++)
  68. edge[++tp] = knew[i], edge[tp].c = -INF;
  69. mst(tp);
  70. for (int i = 1; i <= tp; i++)
  71. if (abs(edge[i].c) != INF)
  72. link(edge[i].x, edge[i].y);
  73. }
  74. void cut2()
  75. {
  76. memcpy(edge, inp, sizeof inp);
  77. mst(m);
  78. int tp = m;
  79. m = 0;
  80. for (int i = 1; i <= tp; i++)
  81. if (edge[i].c != INF) {
  82. inp[++m] = edge[i], inp[m].on_eg = 1;
  83. // printf("Cut2 %d--%lld--%d\n", edge[i].x, edge[i].c, edge[i].y);
  84. }
  85. }
  86. int depth[MAXN], par[MAXN];
  87. long long peo[MAXN];
  88. long long lim[MAXN];
  89. void dfs(int nd, int f)
  90. {
  91. depth[nd] = depth[f]+1;
  92. par[nd] = f, lim[nd] = INF;
  93. peo[nd] = siz[nd];
  94. for (int i = head[nd]; i; i = graph[i].next) {
  95. int to = graph[i].to;
  96. if (to != f) dfs(to, nd), peo[nd] += peo[to];
  97. }
  98. }
  99. void push_lim(int x, int y, long long l)
  100. {
  101. while (x != y) {
  102. if (depth[x] >= depth[y]) {
  103. lim[x] = min(lim[x], l);
  104. x = par[x];
  105. } else {
  106. lim[y] = min(lim[y], l);
  107. y = par[y];
  108. }
  109. }
  110. }
  111. long long deal(int S)
  112. {
  113. memcpy(edge, inp, k*16*sizeof(int));
  114. top = 0;
  115. int tp = m;
  116. // cout << "---" <<edge[1].c << endl;
  117. for (int i = 1; i <= t; i++)
  118. head[stk[i]] = 0;
  119. for (int i = 1; i <= k; i++)
  120. if (S&(1<<(i-1))) {
  121. edge[++tp] = knew[i], edge[tp].c = -INF, edge[tp].on_eg = 1;
  122. if (findgp(knew[i].x) == findgp(knew[i].y)) return 0ll;
  123. }
  124. // for (int i = 1; i <= tp; i++)
  125. // if (edge[i].on_eg != 1)
  126. // throw;
  127. mst(tp, 1, 1);
  128. // printf(" tp = %d \n", tp);
  129. dfs(findgp(1), 0);
  130. long long ans = 0;
  131. for (int i = 1; i <= tp; i++) {
  132. int x = findgp(edge[i].x), y = findgp(edge[i].y);
  133. if (edge[i].on_eg == 0) {
  134. push_lim(x, y, edge[i].c);
  135. // printf("Pushlim %d,%d -- %lld\n", x, y, edge[i].c);
  136. // edge[i].on_eg = 1;
  137. } //else printf("Lk %d -- %lld -- %d\n", x, edge[i].c, y);
  138. }
  139. for (int i = 1; i <= k; i++)
  140. if (S&(1<<(i-1))) {
  141. int x = findgp(knew[i].x), y = findgp(knew[i].y);
  142. if (depth[x] < depth[y]) swap(x, y);
  143. long long l = lim[x];
  144. ans += l*peo[x];
  145. // cout << x << " " << y << " " << l << " " << peo[x] << endl;
  146. }
  147. // cout << ans << endl;
  148. return ans;
  149. }
  150. int main()
  151. {
  152. freopen("toll.in", "r", stdin);
  153. freopen("toll.out", "w", stdout);
  154. scanf("%d%d%d", &n, &m, &k);
  155. for (int i = 1; i <= m; i++)
  156. scanf("%d%d%lld", &inp[i].x, &inp[i].y, &inp[i].c), inp[i].on_eg = 1;
  157. for (int i = 1; i <= k; i++)
  158. scanf("%d%d", &knew[i].x, &knew[i].y);
  159. for (int i = 1; i <= n; i++)
  160. scanf("%lld", &siz[i]);
  161. cut1();
  162. cut2();
  163. for (int i = 1; i <= n; i++)
  164. if (gp[i] == 0)
  165. stk[++t] = i;
  166. long long ans = 0;
  167. for (int i = 0; i < (1<<k); i++) {
  168. ans = max(ans, deal(i));
  169. }
  170. cout << ans << endl;
  171. return 0;
  172. }

bzoj1912: [Apio2010]patrol 巡逻

第一反应是先找最长链,然后缩成一个点再找最长链,然而只有55分。
后来反应过来两个链相交会有损耗,于是看到了大爷题解中把环上边权设为-1再走最长链的方法..
APIO神题好多..知识水平不超过NOIP但是思维难度很大..

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. struct node {
  5. int to, next, dis, neg;
  6. } edge[MAXN*2];
  7. int head[MAXN], top = 0;
  8. void push(int i, int j)
  9. {
  10. top++, edge[top] = (node){j, head[i], 1, top+1}, head[i] = top;
  11. top++, edge[top] = (node){i, head[j], 1, top-1}, head[j] = top;
  12. }
  13. int n, K;
  14. int gp[MAXN], siz[MAXN];
  15. int stk[MAXN], stop = 0;
  16. int ans = 0;
  17. int depth[MAXN], maxl[MAXN], secl[MAXN], maxps[MAXN], secps[MAXN];
  18. int fa[MAXN];
  19. void dfs(int nd, int f = 0)
  20. {
  21. maxl[nd] = secl[nd] = maxps[nd] = secps[nd] = 0;
  22. for (int i = head[nd]; i; i = edge[i].next) {
  23. int to = edge[i].to;
  24. if (to == f) continue;
  25. fa[to] = i;
  26. depth[to] = depth[nd]+1, dfs(to, nd);
  27. if (maxl[to]+edge[i].dis >= maxl[nd]) secl[nd] = maxl[nd], secps[nd] = maxps[nd], maxl[nd] = maxl[to]+edge[i].dis, maxps[nd] = to;
  28. else if (maxl[to]+edge[i].dis > secl[nd]) secl[nd] = maxl[to]+edge[i].dis, secps[nd] = to;
  29. }
  30. }
  31. void deal()
  32. {
  33. memset(depth, 0, sizeof depth);
  34. dfs(1, 0);
  35. //puts("---");
  36. int len = 0, nd;
  37. for (int i = 1; i <= n; i++)
  38. if (maxl[i] + secl[i] > len) len = maxl[i]+secl[i], nd = i;
  39. //puts("---");
  40. ans -= len*2, ans += len+1;
  41. for (int i = maxps[nd]; i; i = maxps[i])
  42. edge[fa[i]].dis = -1, edge[edge[fa[i]].neg].dis = -1;
  43. for (int i = secps[nd]; i; i = maxps[i])
  44. edge[fa[i]].dis = -1, edge[edge[fa[i]].neg].dis = -1;
  45. //puts("---");
  46. }
  47. int main()
  48. {
  49. scanf("%d%d", &n, &K);
  50. memset(gp, 0, sizeof gp);
  51. for (int i = 1; i <= n; i++) siz[i] = 1;
  52. for (int i = 1; i < n; i++) {
  53. int u, v; scanf("%d%d", &u, &v);
  54. push(u, v);
  55. }
  56. ans = (n-1)*2;
  57. deal();
  58. if (K == 2) deal();
  59. cout << ans << endl;
  60. return 0;
  61. }

bzoj1076: [SCOI2008]奖励关

学习一个期望dp..
f(k,S)为第k关,吃掉的情况为S之后的期望得分。如果prev[i]S,f(k,S)=max{f(k+1,S),f(k+1,Si)+v[i]},否咋f(k,S)=f(k+1,S)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. double dp[105][(1<<16)+1];
  4. int k, n;
  5. int rp[105], st[105];
  6. int main()
  7. {
  8. scanf("%d%d", &k, &n);
  9. for (int i = 1; i <= n; i++) {
  10. int t, u;
  11. scanf("%d", &rp[i]);
  12. st[i] = 0;
  13. while (scanf("%d", &u), u != 0)
  14. st[i] |= (1<<(u-1));
  15. }
  16. for (int i = 0; i < (1<<n); i++) dp[k+1][i] = 0;
  17. for (int i = k; i >= 1; i--) {
  18. for (int j = 0; j < (1<<n); j++) {
  19. dp[i][j] = 0;
  20. for (int p = 1; p <= n; p++) {
  21. if ((j&st[p])==st[p])
  22. dp[i][j] += max(dp[i+1][j], dp[i+1][j|(1<<(p-1))]+rp[p]*1.0);
  23. else
  24. dp[i][j] += dp[i+1][j];
  25. }
  26. dp[i][j] /= n;
  27. }
  28. }
  29. printf("%.6f\n", dp[1][0]);
  30. return 0;
  31. }

bzoj2134: 单选错位

分别计算贡献,令a0=an,则第i个题正确的期望是:p(i)=min{ai,ai1}/(aiai1),总和即为所求。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n, A, B, C;
  4. int a[10000005];
  5. int main()
  6. {
  7. scanf("%d%d%d%d%d", &n, &A, &B, &C, a+1);
  8. for (int i=2;i<=n;i++) a[i] = ((long long)a[i-1] * A + B) % 100000001;
  9. for (int i=1;i<=n;i++) a[i] = a[i] % C + 1;
  10. // for (int i = 1; i <= n; i++) cout << a[i] << " "; puts("");
  11. double now = 0;
  12. a[0] = a[n];
  13. for (int i = 1; i <= n; i++) {
  14. now = min(a[i],a[i-1])*1.0/a[i]/a[i-1]+now;
  15. }
  16. printf("%.3f\n", now);
  17. return 0;
  18. }

bzoj4318: OSU!

大力递推可以O(n3)并优化至O(n2)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. double p[100005];
  4. int n;
  5. double dp[100005];
  6. int main()
  7. {
  8. scanf("%d", &n);
  9. for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
  10. for (int i = 1; i <= n; i++) {
  11. dp[i] = 0;
  12. for (int k = 0; k <= i; k++) {
  13. if (k+1 <= i) {
  14. double tmp = 1-p[k];
  15. for (int j = k+1; j <= i; j++)
  16. tmp *= p[j];
  17. dp[i] += tmp*((i-k)*(i-k)*(i-k)+dp[k-1]);
  18. } else dp[i] += dp[k-1]*(1-p[k]);
  19. }
  20. }
  21. cout << dp[n] << endl;
  22. return 0;
  23. }

然而这个做法没有很好地利用期望的线性性质,即E(aX+bY)=aE(X)+bE(Y)。考虑这个元素之前期望的连续1长度为E(x),连续1长度的平方为E(x2),每个元素的贡献为:

(x+1)3x3=3x2+3x+1=3E(x2)+3E(x)+1

注意:E(x2)E2(x)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. double p[100005];
  4. int n;
  5. int main()
  6. {
  7. scanf("%d", &n);
  8. for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
  9. double x, x2, ans; x = x2 = 0, ans = 0;
  10. for (int i = 1; i <= n; i++) {
  11. ans += (x2*3+3*x+1)*p[i];
  12. x2 = (x2+2*x+1)*p[i];
  13. x = (x+1)*p[i];
  14. }
  15. printf("%.1f\n", ans);
  16. return 0;
  17. }

bzoj3036: 绿豆蛙的归宿

例如有12,23,13,24,43,那么13的公式为:

1d1c13+1d11d2(c12+c23)+1d11d21d4(c12+c24+c43)

dpi1i所有路径上点出度倒数乘积乘上路径长的和,fi为路径上所有点出度倒数乘积的和,然后发现有递推关系:

  1. f[to] += f[nd]/d[tp];
  2. dp[to] += dp[nd]/cd[tp]+c(nd,to)*f[nd]/cd[nd];
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. struct node {
  5. int to, next, dis;
  6. } edge[MAXN*2];
  7. int head[MAXN], top = 0, rd[MAXN], cd[MAXN];
  8. void push(int i, int j, int d)
  9. { edge[++top] = (node){j, head[i], d}, head[i] = top, rd[j]++, cd[i]++; }
  10. int stk[MAXN], stop = 0;
  11. int n, m;
  12. double dp[MAXN], f[MAXN];
  13. int main()
  14. {
  15. scanf("%d%d", &n, &m);
  16. for (int i = 1; i <= m; i++) {
  17. int u, v, d;
  18. scanf("%d%d%d", &u, &v, &d);
  19. push(u, v, d);
  20. }
  21. stk[++stop] = 1;
  22. dp[1] = 0, f[1] = 1;
  23. while (stop) {
  24. int tp = stk[stop--];
  25. for (int i = head[tp]; i; i = edge[i].next) {
  26. int to = edge[i].to;
  27. f[to] += f[tp]/cd[tp], dp[to] += dp[tp]/cd[tp]+edge[i].dis*f[tp]/cd[tp];
  28. rd[to]--;
  29. if (rd[to] == 0) stk[++stop] = to;
  30. }
  31. }
  32. printf("%.2f\n", dp[n]);
  33. return 0;
  34. }

bzoj4720: [Noip2016]换教室

终于来填坑了...

考场上设计的状态f[i][j][0/1]表示前i门课,能换j次,这次在哪个教室。然而无论怎么调都有后效性,只能记录路径上概率乘积变爆搜了..

正确的思路应该是f[i][j][0/1]表示前i门课,能换j次,这次提不提出申请,那么转移方程就是:

f[i][j][0]=max{f[i1][j][0]+dis(ci1,ci),(1p[i1])(f[i1][j][1]+dis(ci1,ci))+p[i1](f[i1][j][1]+dis(di1,ci))}

i,j,1同理枚举四种可能情况即可。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n, m, v, e;
  4. int g[505][505];
  5. int c[2005][2];
  6. double k[2005];
  7. double f[2005][2005][2];
  8. int main()
  9. {
  10. scanf("%d%d%d%d", &n, &m, &v, &e);
  11. for (int i = 1; i <= n; i++) scanf("%d", &c[i][0]);
  12. for (int i = 1; i <= n; i++) scanf("%d", &c[i][1]);
  13. for (int i = 1; i <= n; i++) scanf("%lf", &k[i]);
  14. memset(g, 127/3, sizeof g);
  15. for (int i = 1; i <= v; i++) g[i][i] = 0;
  16. for (int i = 1; i <= e; i++) {
  17. int u, v, d; scanf("%d%d%d", &u, &v, &d);
  18. g[u][v] = g[v][u] = min(g[u][v], d);
  19. }
  20. for (int k = 1; k <= v; k++)
  21. for (int i = 1; i <= v; i++)
  22. for (int j = 1; j <= v; j++)
  23. g[j][i] = g[i][j] = min(g[i][j], g[i][k]+g[k][j]);
  24. for (int i = 0; i <= m; i++) f[1][i][0] = f[1][i][1] = 1e10;
  25. f[1][0][0] = f[1][1][1] = f[1][1][0] = 0;
  26. for (int i = 2; i <= n; i++) {
  27. for (register int j = 0; j <= m; j++) {
  28. f[i][j][0] = f[i][j][1] = 1e10;
  29. f[i][j][0] = min(f[i-1][j][0]+g[c[i-1][0]][c[i][0]],
  30. f[i-1][j][1]+k[i-1]*g[c[i-1][1]][c[i][0]]+(1-k[i-1])*g[c[i-1][0]][c[i][0]]);
  31. if (j != 0) {
  32. f[i][j][1] = min(f[i-1][j-1][0]+k[i]*g[c[i-1][0]][c[i][1]]+(1-k[i])*g[c[i-1][0]][c[i][0]],
  33. f[i-1][j-1][1]+k[i]*k[i-1]*g[c[i-1][1]][c[i][1]]+(1-k[i-1])*(1-k[i])*g[c[i-1][0]][c[i][0]]
  34. +k[i]*(1-k[i-1])*g[c[i-1][0]][c[i][1]]+k[i-1]*(1-k[i])*g[c[i-1][1]][c[i][0]]);
  35. f[i][j][0] = min(f[i][j][0], f[i][j-1][0]);
  36. f[i][j][1] = min(f[i][j][1], f[i][j-1][1]);
  37. }
  38. }
  39. }
  40. double ans = f[n][0][0];
  41. for (int i = 1; i <= m; i++) ans = min(f[n][i][1], f[n][i][0]);
  42. printf("%.2f\n", ans);
  43. return 0;
  44. }

bzoj4008: [HNOI2015]亚瑟王

huzecong dalao的神题...
直接dp会发现无论怎么设计状态都不可能消除后效性。
然后就比较神了,分别计算每个卡牌的贡献,如果我们知道了这个卡牌i获得k次发动机会的概率f[i][k],那么其贡献就为:

kf[i][k]×(1(1p[i])k)×di

也就是至少发动一次的概率(即一次也不发动的反面)。而在哪一次发动则对于这个卡牌的贡献是等价的,我们已经通过计算f[i][k]将每个卡牌独立,也就消除了哪一次发动对贡献的影响。然后只要列f[i][k]的方程:

f[i][k]=f[i1][k]×(1p[i1])k+f[i1][k+1]×(1(1p[i1])k+1)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int T, n, r;
  4. double dp[225][140];
  5. double p[225], d[225];
  6. int main()
  7. {
  8. scanf("%d", &T);
  9. while (T--) {
  10. scanf("%d%d", &n, &r);
  11. double tmp = 1;
  12. for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i], &d[i]), tmp *= p[i];
  13. double ans = 0;
  14. memset(dp, 0, sizeof dp);
  15. dp[0][r] = 1;
  16. for (int i = 1; i <= n; i++)
  17. for (int j = 0; j <= r; j++) {
  18. dp[i][j] = dp[i-1][j]*pow(1-p[i-1], j)+dp[i-1][j+1]*(1-pow(1-p[i-1], j+1));
  19. ans += dp[i][j]*(1-pow(1-p[i], j))*d[i];
  20. }
  21. printf("%.10f\n", ans);
  22. }
  23. return 0;
  24. }

bzoj3270: 博物馆

和《游走》那个题套路一样。
把一个有序对看成状态列转移矩阵A,结果向量就是:

λ=0Aλx0=x0IIA

然后就完了。
脑残的我把EA看成A大概需要治疗

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. double A[405][805];
  4. int g[25][25], n, m, u, v, a, b;
  5. double p[25], eps = 1e-10;
  6. inline int num(int i, int j)
  7. { return (i-1)*n+j; }
  8. void inverse()
  9. {
  10. for (int i = 1; i <= n*n; i++) A[i][i+n*n] = 1;
  11. for (int i = 1; i <= n*n; i++) {
  12. int k = i;
  13. while (abs(A[k][i]) <= eps) k++;
  14. swap(A[i], A[k]);
  15. for (int j = 1; j <= n*n; j++) {
  16. if (j == i) continue;
  17. double tmp = -A[j][i]/A[i][i];
  18. for (int k = 1; k <= 2*n*n; k++)
  19. A[j][k] += A[i][k]*tmp;//, printf("%f ",A[j][k]);
  20. }
  21. }
  22. for (int i = 1; i <= n*n; i++)
  23. for (int j = n*n+1; j <= n*n*2; j++)
  24. A[i][j] /= A[i][i];
  25. for (int i = 1; i <= n*n; i++)
  26. for (int j = 1; j <= n*n; j++)
  27. A[i][j] = A[i][j+n*n];
  28. }
  29. int main()
  30. {
  31. scanf("%d%d%d%d", &n, &m, &a, &b);
  32. for (int i = 1; i <= m; i++)
  33. scanf("%d%d", &u, &v), g[u][v] = g[v][u] = 1, g[v][v]++, g[u][u]++;
  34. for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
  35. for (int i = 1; i <= n; i++)
  36. for (int j = 1; j <= n; j++)
  37. for (int k = 1; k <= n; k++)
  38. for (int l = 1; l <= n; l++) { // (i,j)-->(k,l)
  39. if ((i == k || g[i][k]) && (g[j][l] || j==l)) {
  40. double ti = i==k?p[i]:(1-p[i])*1.0/g[i][i];
  41. double tj = j==l?p[j]:(1-p[j])*1.0/g[j][j];
  42. A[num(k,l)][num(i,j)] = -ti*tj;
  43. }
  44. if (i == j)
  45. A[num(k,l)][num(i,j)] = 0;
  46. }
  47. for (int i = 1; i <= n*n; i++) A[i][i] += 1;
  48. inverse();
  49. for (int i = 1; i <= n; i++)
  50. printf("%.6f ", A[num(i,i)][num(a,b)]);
  51. return 0;
  52. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注