2019年杭电多校第一场 1001题blank(DP)HDU6578

2019年杭电多校第一场 1001题blank(DP)HDU6578

    • 解决思路,开一个DP数组来存储0 1 2 3四个字符最后出现的位置,并且在DP中已经==排好序==。
    • DP开四维,DP[i][j][k][2],最后一位开==滚动数组==,用来记录上一个字符串长度时各个位置信息(及滚动继承),i,j,k分别记录==三个字符==的位置,因为无论在什么情况下,必定有一位它最后的位置和字符串的长度相等,所以不用存在dp中,dp只用存三个字符的最后位置。
    • (注意,i,j,k只是按从小到大存储了字符最后出现的位置,而没有指定是哪个字符)
    • dp状态转移方程:
    • 解释:假设当前,0最后出现在i的位置,1最后出现在j的位置,2最后出现在k的位置,3最后出现在==字符串长度==(cur)的位置。在下一次新的情况中,当后一位加上0时,那么按照顺序新3的最后出现的位置为cur-1(即上一个字符串的长度),其余不变,按从小到大,顺序为dp[j][k][cur - 1][now],然后继承上一个。以此类推。
    • 关于限制条件,用一个vector存入,当发现不符合时候,讲对应的DP置换成0。最后符合长度N的所有DP相加即为答案。

题目链接.
参考大佬的代码

解决思路,开一个DP数组来存储0 1 2 3四个字符最后出现的位置,并且在DP中已经排好序

DP开四维,DP[i][j][k][2],最后一位开滚动数组,用来记录上一个字符串长度时各个位置信息(及滚动继承),i,j,k分别记录三个字符的位置,因为无论在什么情况下,必定有一位它最后的位置和字符串的长度相等,所以不用存在dp中,dp只用存三个字符的最后位置。

(注意,i,j,k只是按从小到大存储了字符最后出现的位置,而没有指定是哪个字符)

dp状态转移方程:

dp[i][j][k][now] += dp[i][j][k][last]; // now为当前状态,last为上一次的状态
dp[j][k][cur - 1][now] += dp[i][j][k][last];
dp[i][k][cur - 1][now] += dp[i][j][k][last];
dp[i][j][cur - 1][now] += dp[i][j][k][last];

解释:假设当前,0最后出现在i的位置,1最后出现在j的位置,2最后出现在k的位置,3最后出现在字符串长度(cur)的位置。在下一次新的情况中,当后一位加上0时,那么按照顺序新3的最后出现的位置为cur-1(即上一个字符串的长度),其余不变,按从小到大,顺序为dp[j][k][cur - 1][now],然后继承上一个。以此类推。

关于限制条件,用一个vector存入,当发现不符合时候,讲对应的DP置换成0。最后符合长度N的所有DP相加即为答案。

代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
const int mo = 998244353;
const int N = 107;
int dp[N][N][N][2];
vector<pair<int, int> > d[N];
int main()
{
	int t;
	scanf("%d", &t);
	while (t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		int l, r, x;
		for (int i = 1; i <= n; i++) {
			d[i].clear();//d[i].push_back(make_pair(i, 1));
		}
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%d", &l, &r, &x);
			d[r].push_back(make_pair(l, x));
		}
		memset(dp, 0, sizeof(dp));
		dp[0][0][0][0] = 1;
		for (int cur = 1; cur <= n; cur++) {
			int now = cur & 1;
			int last = now ^ 1;
			for (int i = 0; i <= cur; i++)
				for (int j = i; j <= cur; j++)
					for (int k = j; k <= cur; k++) 
						dp[i][j][k][now] = 0;
			//i
			for (int i = 0; i <= cur; i++)
				for (int j = i; j <= cur; j++)
					for (int k = j; k <= cur; k++) {
						dp[i][j][k][now] += dp[i][j][k][last];
						dp[j][k][cur - 1][now] += dp[i][j][k][last];
						dp[i][k][cur - 1][now] += dp[i][j][k][last];
						dp[i][j][cur - 1][now] += dp[i][j][k][last];

						dp[i][j][k][now] %= mo;
						dp[j][k][cur - 1][now] %= mo;
						dp[i][k][cur - 1][now] %= mo;
						dp[i][j][cur - 1][now] %= mo;
					}
			for (int i = 0; i <= cur; i++)
				for (int j = i; j <= cur; j++)
					for (int k = j; k <= cur; k++)
						for (auto re : d[cur]) {  //遍历d这个数组,写了一个类似标程的写法
							l = re.first, r = cur, x = re.second;
							if (( (i >= l) + (j >= l) + (k >= l) + (cur >= l) ) != x)
								dp[i][j][k][now] = 0;
						}

		}
		int ans= 0;
		for (int i = 0; i <= n; i++)
			for (int j = i; j <= n; j++)
				for (int k = j; k <= n; k++)
					(ans += dp[i][j][k][n & 1]) %= mo;

		printf("%d\n", ans%mo);
		}
	return 0;
}

你可能感兴趣的:(DP)