传送门
【题目分析】
DP好题。。。。但我没做出来qwq。
考虑一个四维的dp:记录dp[pos][i][j][k]表示最后一位为pos,颜色R,G,B最后出现的位置为i,j,k,我们可以考虑将询问离线,将所有询问存在询问的r位置,每当扫到该位置就判是否满足右端点在其右端点的所有询问的限制,如果可行就加上这个方案的方案数。最后统计所有pos=n的位置的答案就行了。
但可以发现pos这一维其实是可以不用的,原因是既然你当前填了颜色,那么一定有一个颜色的最后出现的位置是pos,所以pos可以直接用max(i,j,k)来代替。这样空间也能过了。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=350;
const int MOD=1e9+7;
int n,m;
int ans;
int dp[MAXN][MAXN][MAXN];
vector<pair<int,int> > query[MAXN];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int check(int x,int y,int z){
int pos=max(x,max(y,z));
int siz=query[pos].size();
for(int i=0;i<siz;++i){
int tot=0;
int l=query[pos][i].first,v=query[pos][i].second;
if(x>=l)tot++;
if(y>=l)tot++;
if(z>=l)tot++;
if(tot!=v)
return 0;
}
return 1;
}
int main(){
n=Read(),m=Read();
for(int i=1;i<=m;++i){
int x=Read(),y=Read(),z=Read();
query[y].push_back(make_pair(x,z));
}
dp[0][0][0]=1;
for(int i=0;i<=n;++i){
for(int j=0;j<=n;++j){
for(int k=0;k<=n;++k){
if(!dp[i][j][k])
continue;
if(!check(i,j,k)){
dp[i][j][k]=0;
continue;
}
int pos=max(i,max(j,k));
if(pos==n)
ans=(ans+dp[i][j][k])%MOD;
dp[pos+1][j][k]=(dp[i][j][k]+dp[pos+1][j][k])%MOD;
dp[i][pos+1][k]=(dp[i][j][k]+dp[i][pos+1][k])%MOD;
dp[i][j][pos+1]=(dp[i][j][k]+dp[i][j][pos+1])%MOD;
}
}
}
cout<<ans;
return 0;
}