A. Johny Likes Numbers
题意:找出比\(n\)大的最小的\(k\)的倍数。
求出\(n\)是\(k\)的几倍后加一乘\(k\)。
点击查看代码
void solve() {int n, k;std::cin >> n >> k;std::cout << (n / k + 1) * k << "\n";
}
B. The Same Calendar
题意:给出当前年份,求下一个每天星期数都相等的年份。
首先只有两个年份天数相同才可能,然后考虑枚举,发现\(365 \% 7 = 1, 366 \% 7 = 2\),那么当是闰年就加2,不是就加1,当这个加出来的数是7的倍数就是答案。
点击查看代码
void solve() {int n;std::cin >> n;auto check = [&](int n) -> int {return n % 400 == 0 || (n % 4 == 0 && n % 100 != 0);};int x = check(n);int t = 0;do {++ n;if (check(n)) {t += 366;} else {t += 365;}} while (t % 7 || check(n) != x);std::cout << n << "\n";
}
C. Joty and Chocolate
题意:在\([1, n]\)这些数里,你可以给\(a\)的倍数每个加\(p\)的价值,给\(b\)的倍数每个加\(q\)的价值,每个数只能用一次,求最大价值。
显然我们应该让价值大的染更多的色,并且给更多数染色,那么先给\(a, b\)的倍数都算一遍,然后减去它们重复的倍数的价值就行。
点击查看代码
void solve() {i64 n, a, b, p, q;std::cin >> n >> a >> b >> p >> q;if (p < q) {std::swap(a, b);std::swap(p, q);}i64 ans = 0;ans += n / a * p + n / b * q - n / (a / std::gcd(a, b) * b) * q;std::cout << ans << "\n";
}
D. Iterated Linear Function
题意:一个递归函数:\(f(x) = Ax + B, g(n, x) = f(g(n - 1, x)) n > 0; g(n, x) = x, n = 0\)。求\(g(n, x)\)。
模拟一下,\(g(0, x) = x, g(1, x) = Ax + B, g(2, x) = A^2x + AB + B, g(3, x) = A^3x + A^2B + AB + B\),那么发现最终\(x\)的系数是\(A^n\),然后后面是\(\sum_{i=0}^{n-1} A^i \times B\),发现这是一个等比数列,用等比数列求和公式计算即可。
点击查看代码
void solve() {i64 A, B, n, x;std::cin >> A >> B >> n >> x;if (A == 1) {std::cout << x + (Z)n * B << "\n";return;}//A^n * x + A^n-1 * B + A^n-2 * B.. A^0 * BZ ans = power<Z>(A, n) * x + (1 - power<Z>(A, n)) / (Z)(1 - A) * B;std::cout << ans << "\n";
}
E. Another Sith Tournament
题意:有\(n\)个人要比赛,每场比赛两两对决,第\(i\)个人有\(p[i][j]\)几率战胜第\(j\)个人。你是第一个人,你可以选择第一个上场的人,已经在每场比赛后选一个没上场的人替换失败的人。
看\(n <= 18\),自然想到状压\(dp\),但状态转移有点说法,如果正着做,记\(f[s][i]\)为当前上场过的集合为\(s\),剩下\(i\)的获胜概率,发现转移方程好想,但算出来答案不对,因为有些状态的值不好确定,如果集合有过第一个人,但获胜者不是第一个,概率应该为0,但这样就打乱我们的转移过程。
考虑反着来,\(f[s][i]\)表示\(i\)在擂台上,\(s\)集合的人都可以上场,那么倒着来,\(f[1][0] = 1\),然后对于每个\(f[s][i]\),选一个未上场的\(j\)来和\(i\)打,就有两种结果,取最大值就可以,状态转移方程为\(f[s][i] = \max(f[s][i], f[s - (1 << j)][i] \times p[i][j] + f[1 - (1 << i)][j] \times f[j][i])\)。
点击查看代码
void solve() {int n;std::cin >> n;std::vector p(n, std::vector<double>(n));for (int i = 0; i < n; ++ i) {for (int j = 0; j < n; ++ j) {std::cin >> p[i][j];}}std::vector f(1 << n, std::vector<double>(n));f[1][0] = 1;for (int i = 2; i < 1 << n; ++ i) {for (int j = 0; j < n; ++ j) {if (i >> j & 1) {for (int k = 0; k < n; ++ k) {if ((i >> k & 1) && j != k) {f[i][j] = std::max(f[i][j], f[i - (1 << k)][j] * p[j][k] + f[i - (1 << j)][k] * p[k][j]);}}}}}double ans = 0;for (int i = 0; i < n; ++ i) {ans = std::max(ans, f[(1 << n) - 1][i]);}std::cout << std::fixed << std::setprecision(12);std::cout << ans << "\n";
}