[关闭]
@dxbdly 2022-07-16T17:12:02.000000Z 字数 4875 阅读 166

7.14暑期模拟赛

2022暑


T1 brick

考虑没有奖励砖,那么每一列独立,稍微推一下可以发现是一个背包的模型

设: 表示前 列还剩 颗子弹的最大答案, 为第 列打 个能得到的价值。

考虑加入奖励砖,一个很显然的想法,记录 表示第 列打到第 行要消耗的子弹:

但这样会有个问题,当子弹为 时,下一个是打奖励砖,按照这个方程是打不到这块奖励砖的。

但实际上我们知道,可以通过交换列的顺序打到这块砖,但再手玩几组会发现,这种情况比较复杂,不是很好判断。

题解里给了一个十分神奇的想法,单独拎出最后一颗子弹不打,给 DP 数组增添一维

表示前 列,还剩 枚子弹, 表示没有确定最后一颗子弹的位置, 表示已经确定。

先按照上面的方程转移,但还需要加上一步转移。

当目前的砖是一块普通砖时,可以确定最后一枚子弹打到这块砖上,那么就是:

答案取 即可

  1. //The Code Is From Dawn
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 205;
  14. int n, m, k;
  15. int a[maxn][maxn], b[maxn][maxn], f[maxn][maxn][2], Answer;
  16. signed main() {
  17. // freopen("brick.in", "r", stdin);
  18. // freopen("brick.out", "w", stdout);
  19. n = read(), m = read(), k = read();
  20. if(k == 0) { printf("0\n"); return 0; }
  21. k--;
  22. for(register int i = n; i >= 1; --i)
  23. for(register int j = 1; j <= m; ++j) a[i][j] = read();
  24. for(register int i = n; i >= 1; --i)
  25. for(register int j = 1; j <= m; ++j) b[i][j] = read();
  26. for(register int j = 1; j <= m; ++j) {
  27. for(register int p = 0; p <= k; ++p) f[j][p][0] = f[j - 1][p][0], f[j][p][1] = f[j - 1][p][1];
  28. int Val = 0, Cnt = 0;
  29. for(register int i = 1; i <= n; ++i) {
  30. Val += a[i][j], Cnt += (b[i][j] ^ 1);
  31. for(register int p = 0; p + Cnt <= k; ++p) {
  32. f[j][p][0] = max(f[j][p][0], f[j - 1][p + Cnt][0] + Val);
  33. f[j][p][1] = max(f[j][p][1], f[j - 1][p + Cnt][1] + Val);
  34. }
  35. if(!b[i][j]) {
  36. for(register int p = 0; p + Cnt - 1 <= k; ++p)
  37. f[j][p][1] = max(f[j][p][1], f[j - 1][p + Cnt - 1][0] + Val);
  38. }
  39. }
  40. }
  41. for(register int i = 0; i <= k; ++i) Answer = max(Answer, max(f[m][i][0], f[m][i][1]));
  42. printf("%lld\n", Answer);
  43. return 0;
  44. }

T2 math

简单推柿子题。

可以令: 其中

我们先推 的递推式,由于

把一些东西用 来表示:

把括号拆开,再提出来一些东西:

那么只需要用 表示出 就好了。

展开:

所以

表示:

所以

把它们代到递推式中:

(柿子虽长但很好推)

但这题要求分数形式输出,所以要全程用分数运算。

  1. //The Code Is From Dawn
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 35;
  14. int n, m, k, p;
  15. struct node {
  16. int fz, fm;
  17. }f[maxn];
  18. inline int Gcd(int x, int y) { return y ? Gcd(y, x % y) : x; }
  19. inline node operator + (node x, node y) {
  20. node z; int g = Gcd(x.fm, y.fm);
  21. z.fm = x.fm / g * y.fm;
  22. z.fz = x.fz * (z.fm / x.fm) + y.fz * (z.fm / y.fm);
  23. g = Gcd(z.fz, z.fm), z.fm /= g, z.fz /= g;
  24. return z;
  25. }
  26. inline node operator -(node x, node y) { y.fz = -y.fz; return x + y; }
  27. inline node operator *(node x, node y) {
  28. node z;
  29. z.fz = x.fz * y.fz, z.fm = x.fm * y.fm;
  30. int g = Gcd(z.fz, z.fm); z.fz /= g, z.fm /= g;
  31. return z;
  32. }
  33. inline node operator /(node x, node y) { swap(y.fz, y.fm); return x * y; }
  34. signed main() {
  35. // freopen("math.in", "r", stdin);
  36. // freopen("math.out", "w", stdout);
  37. n = read(), m = read(), k = read(), p = read();
  38. f[1].fz = n, f[2].fz = m, f[3].fz = k;
  39. for(register int i = 1; i <= p; ++i) f[i].fm = 1;
  40. for(register int i = 4; i <= p; ++i) f[i] = (f[1] * f[i - 1]) - ((f[1] * f[1] - f[2]) * (node){1, 2} * f[i - 2]) - ((f[1] * f[2] * (node){1, 2}) - (f[1] * f[1] * f[1] * (node){1, 6}) - (f[3] * (node){1, 3})) * f[i - 3];
  41. printf("%lld/%lld", f[p].fz, f[p].fm);
  42. return 0;
  43. }

T3 xor

一位伟大的哲学家说过:“10道xor的题,有8道是Trie树,1道是线性基,剩下1道是乱搞”

所以考虑先把所有串插进 树, 求出的是 二进制最后的

考虑把所有串倒过来插,把每个串丢到 树上查询,如果有与当前位 的点,就把答案加上其位权乘上经过此点的串数量。

应该算经典套路了。

  1. //The Code Is From Dawn
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? - x : x;
  12. }
  13. const int maxn = 1e5 + 5, mod = 199907210507;
  14. int n, len;
  15. int a[maxn], num[65], Siz[maxn * 60], Trie[maxn * 60][2], tot, Answer;
  16. inline void Change(int x) {
  17. for(register int i = 1; i <= len; ++i) num[i] = 0;
  18. int Cnt = 0;
  19. while(x) num[++Cnt] = x % 2, x >>= 1;
  20. }
  21. inline int Ksm(int x, int y) {
  22. int res = 1;
  23. while(y) {
  24. if(y & 1) res = res * x % mod;
  25. x = x * x % mod, y >>= 1;
  26. }
  27. return res;
  28. }
  29. inline void Insert(int now) {
  30. Change(now);
  31. int x = 0;
  32. for(register int i = 1; i <= len; ++i) {
  33. int ch = num[i];
  34. if(!Trie[x][ch]) Trie[x][ch] = ++tot;
  35. ++Siz[Trie[x][ch]], x = Trie[x][ch];
  36. }
  37. }
  38. inline void Solve(int x, int now) {
  39. if(now == len + 1) return ;
  40. if(Trie[x][num[now] ^ 1]) Answer = (Answer + Ksm(2, now - 1) * Siz[Trie[x][num[now] ^ 1]] % mod) % mod;
  41. if(Trie[x][num[now]]) Solve(Trie[x][num[now]], now + 1);
  42. return ;
  43. }
  44. signed main() {
  45. // freopen("xor.in", "r", stdin);
  46. // freopen("xor.out", "w", stdout);
  47. n = read(), len = 60;
  48. for(register int i = 1; i <= n; ++i) a[i] = read(), Insert(a[i]);
  49. for(register int i = 1; i <= n; ++i) {
  50. Change(a[i]);
  51. Solve(0, 1);
  52. }
  53. printf("%lld\n", Answer);
  54. return 0;
  55. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注