[关闭]
@dxbdly 2022-07-10T13:39:04.000000Z 字数 4223 阅读 230

7.10暑期模拟赛

2022暑


期望得分

T1 T2 T3 Sum
100 0 100 200

实际得分:

T1 T2 T3 Sum
0 0 60 60

惨(woshiSB

T1 Comic

算法:树型DP,组合计数

树上计数,考虑DP

感觉从后往前填比较好填,所以把儿子倒过来

很显然每个儿子互相独立,考虑怎么合并到根上

首先填儿子 ,显然只有一种填法,那么接下来的 () 个 就可以填到 后面的任意一个空

那么就是 但是这样可能会不满足子孙的前后限制,所以还要除一个

所以DP方程:

Tips:错误原因:做插空法的时候考虑总“空隙数”错误

  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 = 1005, mod = 10007;
  14. int T, n, tot;
  15. struct node {
  16. int v, nex;
  17. }edge[maxn << 1];
  18. int head[maxn], len;
  19. int Frac[maxn], Inv[maxn], Answer[maxn], Siz[maxn];
  20. vector <int> E;
  21. inline void make_map(int u, int v) {
  22. len++;
  23. edge[len].nex = head[u];
  24. edge[len].v = v;
  25. head[u] = len;
  26. }
  27. inline int Ksm(int a, int b) {
  28. int res = 1;
  29. while(b) {
  30. if(b & 1) res = res * a % mod;
  31. a = a * a % mod, b >>= 1;
  32. }
  33. return res;
  34. }
  35. inline void Ready() {
  36. Frac[0] = 1, Inv[0] = 1;
  37. for(register int i = 1; i < maxn; ++i) Frac[i] = Frac[i - 1] * i % mod, Inv[i] = Ksm(Frac[i], mod - 2);
  38. }
  39. inline int C(int x, int y) { return Frac[y] * Inv[y - x] % mod * Inv[x] % mod;}
  40. inline void Search(int x) {
  41. Siz[x] = 1, Answer[x] = 1;
  42. if(!head[x]) return ;
  43. for(register int i = head[x]; i; i = edge[i].nex) {
  44. int y = edge[i].v;
  45. Search(y);
  46. if(Siz[y] > 1) Answer[x] = Answer[x] * (Answer[y] * C(Siz[y] - 1, Siz[x] + Siz[y] - 2) % mod) % mod;
  47. Siz[x] += Siz[y];
  48. }
  49. }
  50. signed main() {
  51. // freopen("t1.in", "r", stdin);
  52. // freopen("t1.out", "w", stdout);
  53. T = read(), Ready();
  54. while(T--) {
  55. n = read();
  56. len = 0, memset(head, 0, sizeof(head)), memset(Answer, 0 ,sizeof(Answer)), memset(Siz, 0, sizeof(Siz));
  57. for(register int i = 1; i <= n; ++i) {
  58. tot = read();
  59. E.clear();
  60. for(register int j = 1; j <= tot; ++j) E.push_back(read());
  61. for(register int j = 0; j < E.size(); ++j) make_map(i, E[j]);
  62. }
  63. Search(1);
  64. printf("%lld\n", Answer[1]);
  65. }
  66. return 0;
  67. }

T2 Worried

首先差分,考虑 怎么求

首先想到的是枚每个数最多能多少次方,但这样要枚 ,不可行

考虑枚举次数,那么难点来到怎么求 ,考虑二分,但二分过程中会爆longlong(似乎可以避免,但感觉处理起来很麻烦,不管了)

然后我就感觉这个思路也G了,就没往下想了,下面给出来自 Ew_Corszzm 的两种思路。

思路1:考虑STL的 (才知道 能求 次根),但这样可能有精度问题,所以需要左右调整一下

思路2: 次方可以直接 次方及以上最多 个,所以其实可以直接枚举

但要注意的是,这样求出来的只是 “能够被表示为 次方” 的数,并没有保证最大,所以需要容斥。

可以发现这个容斥和 前缀和很像:

Tips:
日常数据范围没算准,觉得想不到方法的时候可以算一下范围,以防想复杂

当时也没完全相当用容斥,只觉得这东西很难去重,容斥技巧仍需加强

  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 = 64;
  14. int L, R;
  15. int f[maxn + 5];
  16. inline int Calc(int x) {
  17. int Answer = 0;
  18. f[2] = sqrt(x);
  19. for(register int i = 3; i <= maxn; ++i) {
  20. f[i] = 0;
  21. while(pow(f[i] + 1, i) <= x) ++f[i];
  22. f[i]--;
  23. }
  24. for(register int i = 64; i >= 2; --i)
  25. for(register int j = 2; i * j <= 64; ++j) f[i] -= f[i * j];
  26. for(register int i = 2; i <= 64; ++i) Answer += f[i] * (i - 1);
  27. return Answer + x - 1;
  28. }
  29. signed main() {
  30. while((L = read()) && (R = read())) printf("%lld\n", Calc(R) - Calc(L - 1));
  31. return 0;
  32. }

T3 CF

考场上稍微手玩一下,发现第一列可以随便填,考虑其他列填每个位置有什么不同。

若第二个 填在标红的位置,则剩余的矩阵将形成一个 的子问题

若填到未标红位置,相当于不能填红色位置,如果将它也看作一个障碍的话,那就是一个 的子问题

那么可以考虑DP

可以发现,这个DP方程,正好也是错排问题的递推式,那么此题是否与错排问题有关呢?

由上面的分析可以发现,答案与矩阵到底是什么样子无关,只与 有关,所以可以将此矩形特殊化为对角线为1的矩形。

那么就是错排问题的模型了。

Tips:由于此题没给模数,要用高精,然后高精写挂了(,来自 WoshiSB 的小技巧:不需要压位且复杂度较充裕时,可以直接用加法代替乘法

  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, maxm = 1000;
  14. int n;
  15. struct node {
  16. int len;
  17. int s[maxm] = {0};
  18. }f[maxn];
  19. inline node operator + (node a, node b) {
  20. int len = max(a.len, b.len);
  21. int x = 0;
  22. node c;
  23. for(register int i = 1; i <= len; ++i) {
  24. c.s[i] = (a.s[i] + b.s[i] + x) % 10;
  25. x = (a.s[i] + b.s[i] + x) / 10;
  26. }
  27. if(x) c.s[++len] = x; c.len = len;
  28. return c;
  29. }
  30. signed main() {
  31. // freopen("t3.in", "r", stdin);
  32. // freopen("t3.out", "w", stdout);
  33. n = read();
  34. f[1].s[1] = 0, f[1].len = 1, f[0].s[1] = 1, f[0].len = 1;
  35. for(register int i = 2; i <= n; ++i) {
  36. node Cnt = f[i - 1] + f[i - 2];
  37. for(register int j = 1; j < i; ++j) f[i] = f[i] + Cnt;
  38. }
  39. for(register int i = f[n].len; i >= 1; --i) printf("%lld", f[n].s[i]);
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注