[关闭]
@Dmaxiya 2026-03-09T06:06:14.000000Z 字数 7921 阅读 237

2018 Multi-University Training Contest 9

暑期集训


链接:2018 Multi-University Training Contest 9
过题数:3
排名:222
成员:孙昊哲、官展鹏

A. Rikka with Nash Equilibrium

题意

在一个 行 列的矩阵中,定义“纳什均衡点 ”为:第 行第 列的数字比第 行与第 列所有数字都大。

问如果将 个不同的整数放置在这个矩阵内,且每个整数只出现一次的情况下,有多少种方案可以使得矩阵内只有一个纳什均衡点。

输入

第一行一个整数 ,表示有 组数据,接下去 行,每行 个整数 。

数据保证最多 组数据的 。

输出

输出方案数对 取余的结果。

题解

全局只有一个纳什均衡点,这个点只可能是数字 ,从最大的数字往小的数字放,如果前 大的数字已经放过了某 行某 列,则在放置第 大的数字时只能放在这 行于 列内,否则第 大的数字将成为第二个纳什均衡点。

设 表示放前 个数字,覆盖了 行 列的方案数,则有三种情况:

  1. 前 个数字覆盖了 行 列,则第 个数字有 种放法;
  2. 前 个数字覆盖了 行 列,则第 个数字有 种放法;
  3. 前 个数字覆盖了 行 列,则第 个数字有 种放法。

状态转移方程为:

过题代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int maxn = 100;
  5. int T, n, m, nm;
  6. LL MOD;
  7. LL dp[maxn * maxn][maxn][maxn];
  8. int main() {
  9. ios::sync_with_stdio(false);
  10. cin >> T;
  11. while (T--) {
  12. cin >> n >> m >> MOD;
  13. nm = n * m;
  14. dp[1][1][1] = nm;
  15. for (int i = 2; i <= nm; ++i) {
  16. int topj = min(n, i);
  17. for (int j = 1; j <= topj; ++j) {
  18. int topk = min(m, i);
  19. for (int k = 1; k <= topk; ++k) {
  20. dp[i][j][k] = 0;
  21. if (j * k < i) {
  22. continue;
  23. }
  24. dp[i][j][k] = (dp[i - 1][j - 1][k] * (n - j + 1) * k +
  25. dp[i - 1][j][k - 1] * (m - k + 1) * j +
  26. dp[i - 1][j][k] * (j * k - i + 1)) %
  27. MOD;
  28. }
  29. }
  30. }
  31. cout << dp[nm][n][m] << endl;
  32. }
  33. return 0;
  34. }

B. Rikka with Seam

题意

给定一个 行 列的 矩阵,从每一行选择一个位置的数字进行删除,且相邻两行间被删除的数字下标差的绝对值不超过 ,问在执行删除后有多少种不同的剩余矩阵。

输入

第一行一个整数 ,表示有 组数据,每组数据第一行为 个整数 ,接下去 行,每行是一个长度为 的 字符串。

数据保证最多 组数据的 。

输出

输出不同的剩余矩阵数对 取余的结果。

题解

若不考虑重复计算,设 表示删掉第 行第 列的数字得到的方案数,状态转移方程为:


每行按连续的 与连续的 进行分块,可以发现从连续相同的中任意删掉一位,得到的 串都是完全一样的,所以若 ,就会有重复计算的结果。

定义 表示 与 重复计算的方案数,则当 时,,否则:


去重后方案数为:

过题代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int maxn = 2000 + 100;
  5. const int MOD = 998244353;
  6. int T, n, m, k;
  7. char str[maxn][maxn];
  8. int dp[maxn][maxn], sub[maxn][maxn];
  9. int main() {
  10. ios::sync_with_stdio(false);
  11. scanf("%d", &T);
  12. while (T--) {
  13. scanf("%d%d%d", &n, &m, &k);
  14. for (int i = 1; i <= n; ++i) {
  15. scanf("%s", str[i] + 1);
  16. }
  17. for (int j = 1; j <= m; ++j) {
  18. dp[1][j] = j;
  19. sub[1][j] = sub[1][j - 1];
  20. if (str[1][j] == str[1][j - 1]) {
  21. ++sub[1][j];
  22. }
  23. }
  24. for (int i = 2; i <= n; ++i) {
  25. for (int j = 1; j <= m; ++j) {
  26. int l = max(1, j - k);
  27. int r = min(m, j + k);
  28. dp[i][j] = (((dp[i - 1][r] - dp[i - 1][l - 1]) % MOD -
  29. (sub[i - 1][r] - sub[i - 1][l]) % MOD) %
  30. MOD +
  31. MOD) %
  32. MOD;
  33. if (str[i][j] != str[i][j - 1]) {
  34. sub[i][j] = 0;
  35. continue;
  36. }
  37. r = min(m, j + k - 1);
  38. sub[i][j] = (((dp[i - 1][r] - dp[i - 1][l - 1]) % MOD -
  39. (sub[i - 1][r] - sub[i - 1][l]) % MOD) %
  40. MOD +
  41. MOD) %
  42. MOD;
  43. }
  44. for (int j = 1; j <= m; ++j) {
  45. dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
  46. sub[i][j] = (sub[i][j] + sub[i][j - 1]) % MOD;
  47. }
  48. }
  49. printf("%d\n", ((dp[n][m] - sub[n][m]) % MOD + MOD) % MOD);
  50. }
  51. return 0;
  52. }

D. Rikka with Stone-Paper-Scissors

题意

Yuta 与 Rikka 用打牌的方式玩剪刀石头布,三种牌分别为“是石头”、“剪刀”、“布”,Yuta 最开始有 张剪刀、 张石头、 张布,Rikka 最开始有 张剪刀、 张石头、 张布。之前出过的牌后面不能再出,已知 Yuta 随机出牌,Rikka 按最优策略出牌,且后续会根据之前 Yuta 已出过的牌调整出牌策略。Rikka 赢一局加一分,输一局扣一分,平局不得分,问 Rikka 最终得分的期望是多少。

输入

第一行为一个整数 ,接下去有 组数据,每组输入为 个整数 。

输出

对于每组输入,以分数形式输出 Rikka 的期望得分。

题解

不论后续 Rikka 如何采用最优策略,只要 Yuta 出的第一张牌是完全随机的,那 Rikka 后续的最优策略也将得到随机的结果,因此相当于 Rikka 也是随机出牌,计算得分期望为:

过题代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int maxn = 10 + 100;
  5. int T;
  6. LL fenzi, fenmu;
  7. LL a[maxn], b[maxn];
  8. int main() {
  9. ios::sync_with_stdio(false);
  10. cin >> T;
  11. while (T--) {
  12. fenmu = 0;
  13. for (int i = 0; i < 3; ++i) {
  14. cin >> a[i];
  15. fenmu += a[i];
  16. }
  17. for (int i = 0; i < 3; ++i) {
  18. cin >> b[i];
  19. }
  20. fenzi = 0;
  21. for (int i = 0; i < 3; ++i) {
  22. fenzi += b[i] * (a[(i + 2) % 3] - a[(i + 1) % 3]);
  23. }
  24. LL g = __gcd(fenzi, fenmu);
  25. fenzi /= g;
  26. fenmu /= g;
  27. if (fenzi == 0) {
  28. cout << 0 << endl;
  29. continue;
  30. }
  31. if (fenmu < 0) {
  32. fenmu = -fenmu;
  33. fenzi = -fenzi;
  34. }
  35. if (fenmu == 1) {
  36. cout << fenzi << endl;
  37. continue;
  38. }
  39. cout << fenzi << "/" << fenmu << endl;
  40. }
  41. return 0;
  42. }

J. Rikka with Time Complexity

题意

定义函数 个,其中 以 为底。

对于正整数数组 ,定义函数

其中 为数组 的长度为 的后缀子数组。

例如:,。

现在给定数组 和 ,判断 与 的大小关系。

输入

第一行为一个正整数 ,接下去有 组数据;每组数据第一行为两个正整数 ,分别表示数组 与 的长度;第二行为 个整数 ,第三行为 个整数 ,分别表示数组 与 中的数字。

输出

对于每组数据,若 则输出 ,若 趋于 则输出 ,否则输出 。

题解

先考虑数组长度为 时的一般情况,再考虑长度为 时如何兼容。

对 函数取 不影响其相对大小关系,而且还可以把指数项移到系数项,构造出 函数相加 / 相乘的形式:

当底数为 时,取对数次数越多,结果越小,因此 ,在大小比较中取决定作用的是 小的那一项,对于有不同项的乘积相加不容易比较,我们利用 ,给以上的 项配上系数 不影响结果大小,因此当数组长度为 时,我们可以比较以下公式中取 次数较小的项

注意:取 次数较少项在大小比较中起决定性作用,即使与之相乘的另一项次数更多,也不影响比较结果。

比较方式为:定义数组 (其中 数组使用字典序规则比较),比较由题给 数组生成的 与 数组的字典序大小,小的则结果更大。

最后考虑数组长度为 和 的情况,发现上式若将 使用 替换后 结果与 相同, 使用 替换也不影响比较结果,因此当数组长度小于 时,可使用 填充数组长度到 之后再用以上规则进行比较。

过题代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define endl '\n'
  4. typedef long long LL;
  5. const int maxn = 200000 + 100;
  6. int T, a, b, x;
  7. vector<vector<int>> A, B;
  8. vector<int> vct;
  9. vector<vector<int>> convert(const vector<int> &vct) {
  10. vector<vector<int>> p;
  11. if (vct.size() == 1) {
  12. p = {{vct[0] + 2, INT_MAX}, {INT_MAX, INT_MAX}};
  13. } else if (vct.size() == 2) {
  14. p = {{vct[0] + 2, INT_MAX}, {vct[1] + 1, INT_MAX}};
  15. } else {
  16. p = {{vct[0] + 2, INT_MAX}, {vct[1] + 1, vct[2]}};
  17. }
  18. sort(p[0].begin(), p[0].end());
  19. sort(p[1].begin(), p[1].end());
  20. sort(p.begin(), p.end());
  21. return p;
  22. }
  23. int main() {
  24. #ifdef ExRoc
  25. freopen("test.txt", "r", stdin);
  26. #endif // ExRoc
  27. ios::sync_with_stdio(false);
  28. cin >> T;
  29. while (T--) {
  30. cin >> a >> b;
  31. vct.clear();
  32. for (int i = 0; i < a; ++i) {
  33. cin >> x;
  34. vct.push_back(x);
  35. }
  36. A = convert(vct);
  37. vct.clear();
  38. for (int i = 0; i < b; ++i) {
  39. cin >> x;
  40. vct.push_back(x);
  41. }
  42. B = convert(vct);
  43. if (A < B) {
  44. cout << 1 << endl;
  45. } else if (A > B) {
  46. cout << -1 << endl;
  47. } else {
  48. cout << 0 << endl;
  49. }
  50. }
  51. return 0;
  52. }

K. Rikka with Badminton

题意

个学生,有 个学生没球(羽毛球)没拍(羽毛球拍),有 个同学有一个拍但没球,有 个同学有一个球但没拍,有 个同学有一个球和一个拍,其中 。

若要举办一场羽毛球赛,参加的同学拥有的球拍数总和至少为 ,羽毛球数至少为 ,所有同学均有可能参加或者不参加,共 种可能,问所有可能中,有多少种可能无法举办比赛。

输入

第一行为一个整数 ,表示有 组数据,每组数据一行四个整数 ,含义如题。

输出

每组数据输出一行整数,为所求答案对 取模的结果。

题解

穷举所有可能情况的方案数相加:

没球没拍( 人) 有拍没球( 人) 有球没拍( 人) 有球有拍( 人) 方案数
不选 不选 不选 不选
至少 1 人 不选 不选 不选
至少 1 人 至少 1 人 不选 不选
至少 1 人 不选 至少 1 人 不选
至少 1 人 不选 不选 恰好 1 人
至少 1 人 恰好 1 人 至少 1 人 不选
至少 1 人 不选 至少 1 人 恰好 1 人
不选 至少 1 人 不选 不选
不选 恰好 1 人 至少 1 人 不选
不选 不选 至少 1 人 不选
不选 不选 至少 1 人 恰好 1 人
不选 不选 不选 恰好 1 人

过题代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define endl '\n'
  4. typedef long long LL;
  5. const int maxn = 200000 + 100;
  6. const LL MOD = 998244353;
  7. int T;
  8. LL a, b, c, d;
  9. LL fastPow(LL res, LL n) {
  10. LL ans;
  11. for (ans = 1; n != 0; n >>= 1) {
  12. if ((n & 1) != 0) {
  13. ans = ans * res % MOD;
  14. }
  15. res = res * res % MOD;
  16. }
  17. return ans;
  18. }
  19. LL two(LL n) {
  20. return fastPow(2, n);
  21. }
  22. int main() {
  23. #ifdef ExRoc
  24. freopen("test.txt", "r", stdin);
  25. #endif // ExRoc
  26. ios::sync_with_stdio(false);
  27. cin >> T;
  28. while (T--) {
  29. cin >> a >> b >> c >> d;
  30. LL ans = 1
  31. + two(a) - 1
  32. + two(a + b) - 1 - (two(a) - 1) - (two(b) - 1)
  33. + two(a + c) - 1 - (two(a) - 1) - (two(c) - 1)
  34. + (two(a) - 1) * d % MOD
  35. + b * (two(a + c) - 1 - (two(a) - 1 ) - (two(c) - 1)) % MOD
  36. + d * (two(a + c) - 1 - (two(a) - 1) - (two(c) - 1)) % MOD
  37. + two(b) - 1
  38. + b * (two(c) - 1) % MOD
  39. + two(c) - 1
  40. + d * (two(c) - 1) % MOD
  41. + d;
  42. cout << (ans % MOD + MOD) % MOD << endl;
  43. }
  44. return 0;
  45. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注