经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C » 查看文章
牛客NOIP提高组(三)题解
来源:cnblogs  作者:自为风月马前卒  时间:2018/9/26 18:01:09  对本文有异议

心路历程

预计得分:$30 + 0 + 0 = 30$

实际得分:$0+0+0= 0$

T1算概率的时候没模爆long long了。。。

A

我敢打赌这不是noip难度。。。

考虑算一个位置的概率,若想要$k$步把它干掉,那么与他距离为$1$到$k - 1$的点都必须阻塞

且距离为$k$的点至少有一个没被阻塞

概率的处理可以用前缀和优化。

这样看似是$O(n^3 logn)$,但是却不能通过,考虑在前缀和处理的时候有很多没用的状态(超出边界)

加一些剪枝即可

  1. #include<cstdio>
  2. #define max(a, b) (a < b ? b : a)
  3. #define LL long long
  4. using namespace std;
  5. const int MAXN = 201, mod = 1e9 + 7, INF = 1e9 + 10;
  6. inline int read() {
  7. char c = getchar(); int x = 0, f = 1;
  8. while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
  9. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  10. return x * f;
  11. }
  12. int N, M, a[MAXN][MAXN], g[MAXN][MAXN][MAXN], vis[MAXN][MAXN];
  13. LL fastpow(LL a, LL p) {
  14. LL base = 1;
  15. while(p) {
  16. if(p & 1) base = 1ll * base * a % mod;
  17. a = 1ll * a * a % mod; p >>= 1;
  18. }
  19. return base;
  20. }
  21. LL inv(LL a) {
  22. return fastpow(a, mod - 2);
  23. }
  24. int mul(int a, int b) {
  25. if(1ll * a * b > mod) return 1ll * a * b % mod;
  26. else return a * b;
  27. }
  28. void Pre() {
  29. //cout << a[1][1] << endl;
  30. for(int i = 1; i <= N; i++)
  31. for(int j = 1; j <= M; j++)
  32. g[0][i][j] = a[i][j] % mod;
  33. for(int k = 1; k <= max(N, M); k++)
  34. for(int i = 1; i <= N; i++)
  35. for(int j = 1; j <= M; j++) {
  36. if((i - k < 0) || (j - k < 0) || (i + k > N + 1) || (j + k > M + 1)) {vis[i][j] = 1; continue;}
  37. if(vis[i][j]) continue;
  38. g[k][i][j] = mul(g[k - 1][i - 1][j], g[k - 1][i + 1][j]);
  39. if(k > 2) g[k][i][j] = mul(g[k][i][j], inv(g[k - 2][i][j]));
  40. if(k >= 2) g[k][i][j] = mul(mul(g[k][i][j], inv(a[i][j + k - 2])), inv(a[i][j - k + 2]));
  41. g[k][i][j] = mul(mul(g[k][i][j], a[i][j + k]), a[i][j - k]);
  42. }
  43. }
  44. LL calc(int x, int y) {
  45. LL ans = 0, s = a[x][y];
  46. for(int i = 1; i <= max(N, M); i++) {
  47. if((x - i < 0) || (y - i < 0) || (x + i > N + 1) || (y + i > M + 1)) break;
  48. int now = g[i][x][y];
  49. ans = (ans + mul(mul(i, (1 - now + mod)), s)) % mod;
  50. s = mul(s, now);
  51. }
  52. return ans;
  53. }
  54. int main() {
  55. // freopen("a.in", "r", stdin);
  56. N = read(); M = read();
  57. for(LL i = 1; i <= N; i++) {
  58. for(LL j = 1; j <= M; j++) {
  59. LL x = read(), y = read();
  60. a[i][j] = mul(x, inv(y));
  61. }
  62. }
  63. Pre();
  64. for(LL i = 1; i <= N; i++, puts(""))
  65. for(LL j = 1; j <= M; j++)
  66. printf("%lld ", calc(i, j) % mod);
  67. return 0;
  68. }
A

 

B

考场上根本就没时间做。。

题目给出的模型太难处理了,考虑转化成一个较为普通的模型

遇到这种每个点有两个状态的题不难想到拆点,分别表示赢 / 输

当$a$赢了$b$,就从$a$赢向$b$输连边。

这样会得到一个新的无环图,可以证明,两个图中的环是等价的。

直接暴力找最小环即可,时间复杂度:$O(n^2 T)$

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 10005, BIT = 13;
  4. int N, M, dep[MAXN], fa[MAXN][21], MC, U, V;
  5. vector<int> v[MAXN];
  6. int LCA(int x, int y) {
  7. if(dep[x] < dep[y]) swap(x, y);
  8. for(int i = BIT; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
  9. if(x == y) return x;
  10. for(int i = BIT; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
  11. return fa[x][0];
  12. }
  13. void bfs(int x) {
  14. queue<int> q;
  15. q.push(x); dep[x] = 1; fa[x][0] = 0;
  16. while(!q.empty()) {
  17. int p = q.front(); q.pop();
  18. for(int i = 0, to; i < v[p].size(); i++) {
  19. if(!dep[to = v[p][i]]) {
  20. fa[to][0] = p; dep[to] = dep[p] + 1;
  21. for(int j = 1; j <= BIT; j++) fa[to][j] = fa[fa[to][j - 1]][j - 1];
  22. q.push(to);
  23. }
  24. else if(to != fa[p][0]) {
  25. int lca = LCA(p, to), dis = dep[p] + dep[to] - 2 * dep[lca] + 1;
  26. if(dis < MC) MC = dis, U = p, V = to;
  27. }
  28. }
  29. }
  30. }
  31. int main() {
  32. int meiyong; scanf("%d", &meiyong);
  33. while(scanf("%d", &N) && N) {//tag
  34. scanf("%d", &M);
  35. MC = MAXN;
  36. for(int i = 1; i <= 2 * N; i++) v[i].clear();
  37. memset(dep, 0, sizeof(dep));
  38. memset(fa, 0, sizeof(fa));
  39. for(int i = 1; i <= M; i++) {
  40. int x, y; scanf("%d %d", &x, &y);
  41. v[x].push_back(y + N); v[y + N].push_back(x);
  42. }
  43. for(int i = 1; i <= 2 * N; i++) if(!dep[i]) bfs(i);
  44. if(MC == MAXN) {puts("-1");continue;}
  45. int lca = LCA(U, V);
  46. vector<int> ans; ans.clear();
  47. printf("%d\n", MC);
  48. while(U != lca) printf("%d ", (U - 1) % N + 1), U = fa[U][0];
  49. printf("%d", (lca - 1) % N + 1);
  50. while(V != lca) ans.push_back((V - 1) % N + 1), V = fa[V][0];
  51. for(int i = ans.size() - 1; i >= 0; i--) printf(" %d", ans[i]);
  52. puts("");
  53. }
  54. return 0;
  55. }
  56. /*
  57. */
B

C

$k=2$的时候是斐波那契博弈

$k \not = 2$的时候是神仙结论

考虑$k \not = 2$怎么做。

结论:

若$l = n$时先手必输,那么我们找到一个$m = \frac{n}{k} >= n$,且最小的$m$,当$l = n+m$先手也一定必输

证明:

我们把多着的$m$个单独考虑,若$n < l < n+m$时,先手拿走多余的$m$个,后手必败。

但当$l = n +m$时,先手不能拿走$m$个,因为此时后手可以一步拿走剩余的。

不断往下推就行了

  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4. const int MAXN = 1e7 + 10;
  5. int T, k, top;
  6. LL l, sta[MAXN];
  7. int main() {
  8. cin >> T;
  9. while(T--) {
  10. cin >> k >> l;
  11. LL now = 1;
  12. sta[top = 1] = 1;
  13. while(now < l) {
  14. int nxt = lower_bound(sta + 1, sta + top + 1, (now % k == 0) ? now / k : (now / k + 1)) - sta;
  15. sta[++top] = (now = (now + sta[nxt]));
  16. }
  17. puts(now == l ? "DOG" : "GOD");
  18. }
  19. return 0;
  20. }
  21. /*
  22. 1
  23. 2 21
  24. */
C

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号