@Dmaxiya
2026-03-09T06:06:14.000000Z
字数 7921
阅读 15
暑期集训
链接:2018 Multi-University Training Contest 9
过题数:3
排名:222
成员:孙昊哲、官展鹏
在一个 行 列的矩阵中,定义“纳什均衡点 ”为:第 行第 列的数字比第 行与第 列所有数字都大。
问如果将 个不同的整数放置在这个矩阵内,且每个整数只出现一次的情况下,有多少种方案可以使得矩阵内只有一个纳什均衡点。
第一行一个整数 ,表示有 组数据,接下去 行,每行 个整数 。
数据保证最多 组数据的 。
输出方案数对 取余的结果。
全局只有一个纳什均衡点,这个点只可能是数字 ,从最大的数字往小的数字放,如果前 大的数字已经放过了某 行某 列,则在放置第 大的数字时只能放在这 行于 列内,否则第 大的数字将成为第二个纳什均衡点。
设 表示放前 个数字,覆盖了 行 列的方案数,则有三种情况:
- 前 个数字覆盖了 行 列,则第 个数字有 种放法;
- 前 个数字覆盖了 行 列,则第 个数字有 种放法;
- 前 个数字覆盖了 行 列,则第 个数字有 种放法。
状态转移方程为:
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 100;int T, n, m, nm;LL MOD;LL dp[maxn * maxn][maxn][maxn];int main() {ios::sync_with_stdio(false);cin >> T;while (T--) {cin >> n >> m >> MOD;nm = n * m;dp[1][1][1] = nm;for (int i = 2; i <= nm; ++i) {int topj = min(n, i);for (int j = 1; j <= topj; ++j) {int topk = min(m, i);for (int k = 1; k <= topk; ++k) {dp[i][j][k] = 0;if (j * k < i) {continue;}dp[i][j][k] = (dp[i - 1][j - 1][k] * (n - j + 1) * k +dp[i - 1][j][k - 1] * (m - k + 1) * j +dp[i - 1][j][k] * (j * k - i + 1)) %MOD;}}}cout << dp[nm][n][m] << endl;}return 0;}
给定一个 行 列的 矩阵,从每一行选择一个位置的数字进行删除,且相邻两行间被删除的数字下标差的绝对值不超过 ,问在执行删除后有多少种不同的剩余矩阵。
第一行一个整数 ,表示有 组数据,每组数据第一行为 个整数 ,接下去 行,每行是一个长度为 的 字符串。
数据保证最多 组数据的 。
输出不同的剩余矩阵数对 取余的结果。
若不考虑重复计算,设 表示删掉第 行第 列的数字得到的方案数,状态转移方程为:
每行按连续的 与连续的 进行分块,可以发现从连续相同的中任意删掉一位,得到的 串都是完全一样的,所以若 ,就会有重复计算的结果。定义 表示 与 重复计算的方案数,则当 时,,否则:
去重后方案数为:
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 2000 + 100;const int MOD = 998244353;int T, n, m, k;char str[maxn][maxn];int dp[maxn][maxn], sub[maxn][maxn];int main() {ios::sync_with_stdio(false);scanf("%d", &T);while (T--) {scanf("%d%d%d", &n, &m, &k);for (int i = 1; i <= n; ++i) {scanf("%s", str[i] + 1);}for (int j = 1; j <= m; ++j) {dp[1][j] = j;sub[1][j] = sub[1][j - 1];if (str[1][j] == str[1][j - 1]) {++sub[1][j];}}for (int i = 2; i <= n; ++i) {for (int j = 1; j <= m; ++j) {int l = max(1, j - k);int r = min(m, j + k);dp[i][j] = (((dp[i - 1][r] - dp[i - 1][l - 1]) % MOD -(sub[i - 1][r] - sub[i - 1][l]) % MOD) %MOD +MOD) %MOD;if (str[i][j] != str[i][j - 1]) {sub[i][j] = 0;continue;}r = min(m, j + k - 1);sub[i][j] = (((dp[i - 1][r] - dp[i - 1][l - 1]) % MOD -(sub[i - 1][r] - sub[i - 1][l]) % MOD) %MOD +MOD) %MOD;}for (int j = 1; j <= m; ++j) {dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;sub[i][j] = (sub[i][j] + sub[i][j - 1]) % MOD;}}printf("%d\n", ((dp[n][m] - sub[n][m]) % MOD + MOD) % MOD);}return 0;}
Yuta 与 Rikka 用打牌的方式玩剪刀石头布,三种牌分别为“是石头”、“剪刀”、“布”,Yuta 最开始有 张剪刀、 张石头、 张布,Rikka 最开始有 张剪刀、 张石头、 张布。之前出过的牌后面不能再出,已知 Yuta 随机出牌,Rikka 按最优策略出牌,且后续会根据之前 Yuta 已出过的牌调整出牌策略。Rikka 赢一局加一分,输一局扣一分,平局不得分,问 Rikka 最终得分的期望是多少。
第一行为一个整数 ,接下去有 组数据,每组输入为 个整数 。
对于每组输入,以分数形式输出 Rikka 的期望得分。
不论后续 Rikka 如何采用最优策略,只要 Yuta 出的第一张牌是完全随机的,那 Rikka 后续的最优策略也将得到随机的结果,因此相当于 Rikka 也是随机出牌,计算得分期望为:
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 10 + 100;int T;LL fenzi, fenmu;LL a[maxn], b[maxn];int main() {ios::sync_with_stdio(false);cin >> T;while (T--) {fenmu = 0;for (int i = 0; i < 3; ++i) {cin >> a[i];fenmu += a[i];}for (int i = 0; i < 3; ++i) {cin >> b[i];}fenzi = 0;for (int i = 0; i < 3; ++i) {fenzi += b[i] * (a[(i + 2) % 3] - a[(i + 1) % 3]);}LL g = __gcd(fenzi, fenmu);fenzi /= g;fenmu /= g;if (fenzi == 0) {cout << 0 << endl;continue;}if (fenmu < 0) {fenmu = -fenmu;fenzi = -fenzi;}if (fenmu == 1) {cout << fenzi << endl;continue;}cout << fenzi << "/" << fenmu << endl;}return 0;}
定义函数 ,其中 以 为底。
对于正整数数组 ,定义函数
其中 为数组 的长度为 的后缀子数组。
例如:,。
现在给定数组 和 ,判断 与 的大小关系。
第一行为一个正整数 ,接下去有 组数据;每组数据第一行为两个正整数 ,分别表示数组 与 的长度;第二行为 个整数 ,第三行为 个整数 ,分别表示数组 与 中的数字。
对于每组数据,若 则输出 ,若 趋于 则输出 ,否则输出 。
先考虑数组长度为 时的一般情况,再考虑长度为 时如何兼容。
对 函数取 不影响其相对大小关系,而且还可以把指数项移到系数项,构造出 函数相加 / 相乘的形式:
当底数为 时,取对数次数越多,结果越小,因此 ,在大小比较中取决定作用的是 小的那一项,对于有不同项的乘积相加不容易比较,我们利用 ,给以上的 项配上系数 不影响结果大小,因此当数组长度为 时,我们可以比较以下公式中取 次数较小的项
注意:取 次数较少项在大小比较中起决定性作用,即使与之相乘的另一项次数更多,也不影响比较结果。
比较方式为:定义数组 (其中 数组使用字典序规则比较),比较由题给 数组生成的 与 数组的字典序大小,小的则结果更大。
最后考虑数组长度为 和 的情况,发现上式若将 使用 替换后 结果与 相同, 使用 替换也不影响比较结果,因此当数组长度小于 时,可使用 填充数组长度到 之后再用以上规则进行比较。
#include<bits/stdc++.h>using namespace std;#define endl '\n'typedef long long LL;const int maxn = 200000 + 100;int T, a, b, x;vector<vector<int>> A, B;vector<int> vct;vector<vector<int>> convert(const vector<int> &vct) {vector<vector<int>> p;if (vct.size() == 1) {p = {{vct[0] + 2, INT_MAX}, {INT_MAX, INT_MAX}};} else if (vct.size() == 2) {p = {{vct[0] + 2, INT_MAX}, {vct[1] + 1, INT_MAX}};} else {p = {{vct[0] + 2, INT_MAX}, {vct[1] + 1, vct[2]}};}sort(p[0].begin(), p[0].end());sort(p[1].begin(), p[1].end());sort(p.begin(), p.end());return p;}int main() {#ifdef ExRocfreopen("test.txt", "r", stdin);#endif // ExRocios::sync_with_stdio(false);cin >> T;while (T--) {cin >> a >> b;vct.clear();for (int i = 0; i < a; ++i) {cin >> x;vct.push_back(x);}A = convert(vct);vct.clear();for (int i = 0; i < b; ++i) {cin >> x;vct.push_back(x);}B = convert(vct);if (A < B) {cout << 1 << endl;} else if (A > B) {cout << -1 << endl;} else {cout << 0 << endl;}}return 0;}
个学生,有 个学生没球(羽毛球)没拍(羽毛球拍),有 个同学有一个拍但没球,有 个同学有一个球但没拍,有 个同学有一个球和一个拍,其中 。
若要举办一场羽毛球赛,参加的同学拥有的球拍数总和至少为 ,羽毛球数至少为 ,所有同学均有可能参加或者不参加,共 种可能,问所有可能中,有多少种可能无法举办比赛。
第一行为一个整数 ,表示有 组数据,每组数据一行四个整数 ,含义如题。
每组数据输出一行整数,为所求答案对 取模的结果。
穷举所有可能情况的方案数相加:
没球没拍( 人) 有拍没球( 人) 有球没拍( 人) 有球有拍( 人) 方案数 不选 不选 不选 不选 至少 1 人 不选 不选 不选 至少 1 人 至少 1 人 不选 不选 至少 1 人 不选 至少 1 人 不选 至少 1 人 不选 不选 恰好 1 人 至少 1 人 恰好 1 人 至少 1 人 不选 至少 1 人 不选 至少 1 人 恰好 1 人 不选 至少 1 人 不选 不选 不选 恰好 1 人 至少 1 人 不选 不选 不选 至少 1 人 不选 不选 不选 至少 1 人 恰好 1 人 不选 不选 不选 恰好 1 人
#include<bits/stdc++.h>using namespace std;#define endl '\n'typedef long long LL;const int maxn = 200000 + 100;const LL MOD = 998244353;int T;LL a, b, c, d;LL fastPow(LL res, LL n) {LL ans;for (ans = 1; n != 0; n >>= 1) {if ((n & 1) != 0) {ans = ans * res % MOD;}res = res * res % MOD;}return ans;}LL two(LL n) {return fastPow(2, n);}int main() {#ifdef ExRocfreopen("test.txt", "r", stdin);#endif // ExRocios::sync_with_stdio(false);cin >> T;while (T--) {cin >> a >> b >> c >> d;LL ans = 1+ two(a) - 1+ two(a + b) - 1 - (two(a) - 1) - (two(b) - 1)+ two(a + c) - 1 - (two(a) - 1) - (two(c) - 1)+ (two(a) - 1) * d % MOD+ b * (two(a + c) - 1 - (two(a) - 1 ) - (two(c) - 1)) % MOD+ d * (two(a + c) - 1 - (two(a) - 1) - (two(c) - 1)) % MOD+ two(b) - 1+ b * (two(c) - 1) % MOD+ two(c) - 1+ d * (two(c) - 1) % MOD+ d;cout << (ans % MOD + MOD) % MOD << endl;}return 0;}