2019hdu多校第一场A题Blank(dp,时空优化)

http://acm.hdu.edu.cn/showproblem.php?pid=6578

题目描述

There are N blanks arranged in a row. The blanks are numbered 1,2,…,N from left to right.
Tom is filling each blank with one number in {0,1,2,3}. According to his thought, the following M conditions must all be satisfied. The ith condition is:
There are exactly xi different numbers among blanks ∈[li,ri].
In how many ways can the blanks be filled to satisfy all the conditions? Find the answer modulo 998244353.

 

 

输入

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.
In each test case, there are two integers n(1≤n≤100) and m(0≤m≤100) in the first line, denoting the number of blanks and the number of conditions.
For the following m lines, each line contains three integers l,r and x, denoting a condition(1≤l≤r≤n, 1≤x≤4).

 

输出

For each testcase, output a single line containing an integer, denoting the number of ways to paint the blanks satisfying all the conditions modulo 998244353.

 

样例输入

复制样例数据

2
1 0
4 1
1 3 3

样例输出

4
96

T组样例,

让你求长度为n的序列种数(有m个限制,在[li,ri]区间内要有且仅有xi种数)pos

朴素想法,dp[len][p0][p1][p2][p3],长度为len的序列,最后一个0的下标是p0,最后一个1的下标是p1,……

先不考虑时间问题,很明显内存不够,1e10

长度为len的序列肯定是从长度为len-1的序列推过来的,所以第一维可以01滚动

另外,既然是长度为len的序列,那么p0,p1,p2,p3中必有一个是len,我们可以考虑将其与第一维合并(共用),但哪个数的下标是len呢,很迷~~~

很明显,每个p实际上不止代表着下标,也代表这种数(除了没用这个数的时候都是0,用了的话最后一次出现的下标都是唯一的,不可能一个位置有两种数),也就是说有几个p在限制范围内,该范围内就有几种数。与至于是pi大还是pj无关,那么我们可以把4个p按非递增顺序排个序,排完序后一样的看做一种状态

定义dp[i][j][k][t]为填完前i个位置后,{0,1,2,3}这4个数字最后一次出现的位置,排序后为i,j,k,t(i>=j>=k>=t),枚举第i位数字是由谁转移过来的

dp[i][j][k][t]+=dp[i-1][j][k][t](下标为i的位置,放的数和最后一次出现位置的下标为i-1位置的数一样)

dp[i][i-1][k][t]+=dp[i-1][j][k][t](下标为i的位置,放的数和最后一次出现位置的下标为j位置的数一样)

dp[i][i-1][j][t]+=dp[i-1][j][k][t](下标为i的位置,放的数和最后一次出现位置的下标为k位置的数一样)

dp[i][i-1][j][k]+=dp[i-1][j][k][t](下标为i的位置,放的数和最后一次出现位置的下标为t位置的数一样)

然后把第一维01滚动,空间优化成了2*1e6,时间复杂度也从O(n^5)优化到了O(n^4)

这是没有限制的情况,有限制怎么办?加判断!

一个下标代表一种数,对于每个限制区间右端点等于i的限制,

if((1+(j>=lim[pos].l)+(k>=lim[pos].l)+(t>=lim[pos].l))!=lim[pos].x)
	dp[p][j][k][t]=0;

不符合限制,那就不能给后面提供贡献,就是0

对于限制区间右端点为i区间存的时候要处理好,可以用个vector存,v[i]储存右端点为i的所有区间,这样判断的时候能省很多时间

struct node{
	int l,r,x;
}lim[105];
int v[105][105],tail[105];

我用二维数组模拟的vector,v[i]储存右端点下标为i的区间在lim中的下标,这样下标就能跳着找了,不用for循环1~m了

(这里排不排序没有影响,反正该判断的区间都得判断,跑不了,嘤嘤嘤)

%杜教%杜教%杜教

#include
using namespace std;
typedef long long ll;
const int mod=998244353;
int dp[2][101][101][101];
struct node{
	int l,r,x;
}lim[105];
//bool cmp(node a,node b){
//	if(a.r!=b.r) return a.r=lim[pos].l)+(k>=lim[pos].l)+(t>=lim[pos].l))!=lim[pos].x)
							dp[p][j][k][t]=0;
						}
					}
				}
			}
		}
		ll ans=0;
		for(int i=0;i

 

你可能感兴趣的:(动态规划DP)