HDU 6578 Blank

47 篇文章 0 订阅

题目大意:长度为n的数组要求分别填入0到3四个数中的任意一个,有m个限制条件:区间[l,r]中出现的数字种数恰好为x,求方案数。

记录4种数字最后出现的位置在限制条件下的方案数(及时清零)然后DP。
发现具体是那种数字不重要,于是记录4种数字从后到前最后出现的位置就可以让状态数 ÷ 4 ! \div 4! ÷4!
然后 O ( n 4 T ) O(n^4T) O(n4T)的奇妙卡常就能过了。

AC Code:

#include<bits/stdc++.h>
#define maxn 105
#define mod 998244353
#define inf 0x3f3f3f3f
using namespace std;

int n,m,f[2][maxn][maxn][maxn],l[2][maxn][5];
bool check(int a,int b,int c,int d,int e){
	if(l[1][e][1] < inf && b>=l[1][e][1]) return 0;
	if((l[1][e][2] < inf && c>=l[1][e][2]) || (l[0][e][2] > -1 && b<l[0][e][2])) return 0;
	if((l[1][e][3] < inf && d>=l[1][e][3]) || (l[0][e][3] > -1 && c<l[0][e][3])) return 0;
	if((l[0][e][4] > -1 && d < l[0][e][4])) return 0;
	return 1;
}

int sol(int a){return a>=mod?a-mod:a; }

int main(){
	
//	freopen("1.in","r",stdin);
	
	int T;scanf("%d",&T);
	for(;T--;){
		scanf("%d%d",&n,&m);
		memset(l[0],-1,sizeof l[0]);
		memset(l[1],0x3f,sizeof l[1]);
		for(int i=1;i<=m;i++){
			int L,R,x;scanf("%d%d%d",&L,&R,&x);
			l[0][R][x] = max(l[0][R][x] , L);
			l[1][R][x] = min(l[1][R][x] , L);
		}
		
		int now = 1 , pre = 0;
		memset(f,0,sizeof f);
		f[pre][0][0][0] = 1;
		for(int a=1;a<=n;a++,swap(now,pre)){
			for(int a1=0;a1<max(a-1,1);a1++)
				for(int a2=0;a2<max(a1,1);a2++)
					for(int a3=0;a3<max(a2,1);a3++)
						if(f[pre][a1][a2][a3]){
							//if(check(a,a1,a2,a3,a)) 
								f[now][a1][a2][a3] = sol(f[now][a1][a2][a3] + f[pre][a1][a2][a3]);
							//if(check(a,a-1,a2,a3,a)) 
								f[now][a-1][a2][a3] = sol(f[now][a-1][a2][a3] + f[pre][a1][a2][a3]);
							//if(check(a,a-1,a1,a3,a)) 
								f[now][a-1][a1][a3] = sol(f[now][a-1][a1][a3] + f[pre][a1][a2][a3]);
							//if(check(a,a-1,a1,a2,a)) 
								f[now][a-1][a1][a2] = sol(f[now][a-1][a1][a2] + f[pre][a1][a2][a3]);
							f[pre][a1][a2][a3] = 0;
						}
			for(int a1=0;a1<a;a1++)
				for(int a2=0;a2<max(a1,1);a2++)
					for(int a3=0;a3<max(a2,1);a3++)
						if(!check(a,a1,a2,a3,a))
							f[now][a1][a2][a3] = 0;
		}
		int ans = 0;
		for(int a1=0;a1<max(n,1);a1++)
			for(int a2=0;a2<max(a1,1);a2++)
				for(int a3=0;a3<max(a2,1);a3++)	
					ans = sol(ans + f[pre][a1][a2][a3]);
		printf("%d\n",(ans+mod)%mod);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值