题意
n个格子排成一行,每个格子可以涂四种颜色。
给m个形如(l,r,x)的限制,表示l到r格子内恰好有x种颜色
问满足所有限制的涂色方法有多少种
n<=100,m<=100
做法
dp,设f[i,j,k,l]表示四种颜色分别在i、j、k、l出现了最后一次,由于四种颜色调换顺序其实是一样的所以我们可以钦定i<=j<=k<=l
向后转移的时候判断当前状态是否满足限制即可,注意滚动和清空数组的问题
代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
const int MOD=998244353;
int f[2][105][105][105];
int p[105],u[105][105],v[105][105];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
bool check(int i,int j,int k,int l) {
if (!i&&!j&&!k&&!l) return true;
if ((i==j)&&(i)) return false;
if ((k==j)&&(k)) return false;
if ((k==l)&&(k)) return false;
return true;
}
void upd(int &x,int v) {
x+=v; (x>=MOD)?(x-=MOD):0;
}
int main(void) {
for (int T=read();T--;) {
int n=read(),m=read();
rep(i,1,n) p[i]=0;
rep(i,1,m) {
int l=read(),r=read(),x=read();
p[r]++;
v[r][p[r]]=l;
u[r][p[r]]=x;
}
rep(i,0,1) rep(j,0,i) rep(k,0,j) f[0][i][j][k]=f[1][i][j][k]=0;
f[0][0][0][0]=1;
rep(i,0,n) {
rep(j,0,i) rep(k,0,j) rep(l,0,k) f[!(i&1)][j][k][l]=0;
rep(j,0,i) rep(k,0,j) rep(l,0,k) {
if (!check(i,j,k,l)) continue;
bool flag=false;
rep(tx,1,p[i]) {
int xf=v[i][tx],xs=u[i][tx];
int tmp=(n>=xf)+(j>=xf)+(k>=xf)+(l>=xf);
if (tmp!=xs) {
flag=true; break;
}
}
if (flag) continue;
int x=f[i&1][j][k][l];
upd(f[!(i&1)][j][k][l],x);
upd(f[!(i&1)][i][j][k],x);
upd(f[!(i&1)][i][k][l],x);
upd(f[!(i&1)][i][j][l],x);
}
}
int ans=0;
rep(j,0,n) rep(k,0,j) rep(l,0,k) {
if (!check(n,j,k,l)) continue;
bool flag=false;
rep(tx,1,p[n]) {
int xf=v[n][tx],xs=u[n][tx];
int tmp=(n>=xf)+(j>=xf)+(k>=xf)+(l>=xf);
if (tmp!=xs) {
flag=true; break;
}
}
if (flag) continue;
upd(ans,f[n&1][j][k][l]);
}
printf("%d\n", ans);
}
return 0;
}