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

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. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注