做题记录 // 230214

情人,情人,情人节!

A. #4681. mm 和 tt 吃糖果

http://222.180.160.110:1024/contest/3302/problem/1

不难想到把题目抽象成图论模型……

记得上一次我说这话的时候还是在幻想乡修 wifi。然后抽象完了就寄了。

不妨把某个点和所有位于其右下方的点连边,然后跑一个拓扑排序,对每个结点记录最大值(表示第一次走)与次大值(表示第二次走),然后很玄学地为只最大值加上当前点权……

理所当然地寄了。

不妨参考下面这组 Hack:

Input

3 3
1 2 4
2 3 5
1 3 4
Output
13

原因很简单,这么做的话 \((1,2)\) 既会更新 \((1,3)\),也会更新 \((2,3)\)

所以我们只能 DP…… 不难想到四维 DP,使用 f[i][j][k][l] 表示第一次走到 \((i,j)\),第二次走到 \((k,l)\) 的最大价值。

这个同时走的思想就很妙。因为只能朝右朝下走,走到某个点所花费的步数是一定的,也就是说不存在第一次花费 \(s\) 步走到 \((x,y)\),第二次需要花费 \((s+1)\) 步的情况。

好妙啊,为什么所有人都认为这个思路转折点很一眼呢???可以退役啦!

namespace XSC062 {
using namespace fastIO;
const int maxn = 25;
int n, k, x, y;
int a[maxn][maxn];
int f[maxn][maxn][maxn][maxn];
inline int max(int x, int y) {
	return x > y ? x : y;
}
int main() {
	read(n), read(k);
	while (k--)
		read(x), read(y), read(a[x][y]);
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			for (int k = 1; k <= n; ++k) {
				for (int l = 1; l <= n; ++l) {
					if (i == k && j == l) {
						f[i][j][k][l] = max(f[i][j][k][l],
								f[i - 1][j][k - 1][l] + a[i][j]);
						f[i][j][k][l] = max(f[i][j][k][l],
								f[i - 1][j][k][l - 1] + a[i][j]);
						f[i][j][k][l] = max(f[i][j][k][l],
								f[i][j - 1][k - 1][l] + a[i][j]);
						f[i][j][k][l] = max(f[i][j][k][l],
								f[i][j - 1][k][l - 1] + a[i][j]);
					}
					else {
						f[i][j][k][l] = max(f[i][j][k][l],
									f[i - 1][j][k - 1][l]
									+ a[i][j] + a[k][l]);
						f[i][j][k][l] = max(f[i][j][k][l],
									f[i - 1][j][k][l - 1]
									+ a[i][j] + a[k][l]);
						f[i][j][k][l] = max(f[i][j][k][l],
									f[i][j - 1][k - 1][l]
									+ a[i][j] + a[k][l]);
						f[i][j][k][l] = max(f[i][j][k][l],
									f[i][j - 1][k][l - 1]
									+ a[i][j] + a[k][l]);
					}
				}
			}
		}
	}
	print(f[n][n][n][n]);
	return 0;
}
} // namespace XSC062

B. mob 的科学麻将

http://222.180.160.110:1024/contest/3302/problem/2

牛逼题!反正我是一辈子想不出来!

std 如下,注释是我打的!

#include <cstdio>
#define int long long
const int mod = 1e9 + 7;
int dp[2][13][5005];
int pv, x, p, v, ans;
int n, m, i, j, k, nw;
signed main() {
    scanf("%lld%lld", &n, &m);
    pv = m;
    // p: m 是 2 的几次方
    while ((pv & 1) == 0)
		p++, pv >>= 1; // 处理系数 
    for (i = 1; i <= n; i++) {
        nw = !nw; // 滚动 
        scanf("%lld", &x);
        for (j = 0; j <= p; j++) {
            for (k = 0; k < (m >> j); k++) {
                // 继承
                dp[nw][j][k] = dp[!nw][j][k];
                v = (k - (x % (m >> j)) + (m >> j))
                                            % (m >> j);
                if (j > 0) {
                    dp[nw][j][k] = (dp[nw][j][k] +
                        dp[!nw][j - 1][v] + dp[!nw]
                        [j - 1][v + (m >> j)]) % mod;
                }
                if (j == 0) {
                    if (k == x % m) {
                        dp[nw][j][k] =
                            (dp[nw][j][k] + 1) % mod;
                    }
                }
                if (j == p) {
                    dp[nw][j][k] = (dp[nw][j][k] +
                                dp[!nw][j][v]) % mod;
                }
            }
        }
    }
    for (i = 0; i <= p; i++)
        ans = (ans + dp[nw][i][0]) % mod;
    printf("%lld\n", ans);
    return 0;
}

C. mob 的《麻将与概率系统导论》

http://222.180.160.110:1024/contest/3302/problem/3

std 如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n, i, m, x, y, j, S, high_bit[131072], p[131072], dp[131072];
const ll mod = 998244353;
int main() {
    scanf("%lld", &n);
    for (i = 0; i < 131072; i++)
        for (j = 0; j < 17; j++)
            if ((1 << j) & i)
                high_bit[i] = 1 << j;
    for (i = 1; i <= n; i++) {
        scanf("%lld%lld", &x, &y);
        p[y] = (p[y] + x) % mod;
    }
    dp[0] = 1;
    for (i = 1; i < 131072; i++) {
        S = i - high_bit[i];
        for (j = S; j; j = (j - 1) & S) dp[i] = (dp[i] + p[j + high_bit[i]] * dp[i - j - high_bit[i]]) % mod;
        dp[i] = (dp[i] + p[high_bit[i]] * dp[i - high_bit[i]]) % mod;
    }
    scanf("%lld", &m);
    for (i = 1; i <= m; i++) {
        scanf("%lld", &x);
        printf("%lld\n", dp[x]);
    }
    return 0;
}
posted @ 2023-02-18 16:54  XSC062  阅读(22)  评论(0编辑  收藏  举报