【题目】
题目描述:
有 n n n 个方格排成一列。现在有 3 3 3 个颜色 R,G,B,给出 m m m 个限制条件 l , r , v l,r,v l,r,v,要求对于区间 [ l l l , , , r r r ] 必须有 v v v 种颜色。问:满足所有条件的方案数。
输入格式:
第一行是 n , m ( 1 ≤ n , m ≤ 300 ) n,m(1≤n,m≤300) n,m(1≤n,m≤300)。
接下来是 m m m 行,每行 3 3 3 个整数 l i , r i , v i ( 1 ≤ l i ≤ r i ≤ n , 1 ≤ v i ≤ 3 ) l_i,r_i,v_i(1≤l_i≤r_i≤n,1≤v_i≤3) li,ri,vi(1≤li≤ri≤n,1≤vi≤3)。
输出格式:
输出一个整数表示方案数,对 1 0 9 + 7 10^9+7 109+7 取模。
样例数据:
【样例 1 1 1】
输入
4 2
1 3 1
2 4 2
输出
6
【样例 2 2 2】
输入
8 10
2 6 2
5 5 1
3 5 2
4 7 3
4 4 1
2 3 1
7 7 1
1 5 2
1 7 3
3 4 2
输出
108
提示:
【样例 1 1 1 解释】
RRRG
RRRB
GGGR
GGGB
BBBR
BBBG
【分析】
这道题输出 0 就有好多好多分的。
这道题的正解是 d p dp dp 啊,我依旧没有想出来啊。
定义 f [ p o s ] [ i ] [ j ] [ k ] f[pos][i][j][k] f[pos][i][j][k] 为执行到 p o s pos pos 位,第 1 1 1 种颜色最后出现在 i i i 位置,第 2 2 2 种颜色最后出现在 j j j 位置,第 3 3 3 种颜色最后出现在 k k k 位置时的方案数。
首先是判断这种状态是否合法。我们将以 x x x 为右端点的限制条件保存在 v e c x vec_x vecx 中,取出 v e c p o s vec_{pos} vecpos 里的所有限制条件,对于一个限制条件,判断里面的颜色个数以否等于 v v v 即可,若不等,则该状态不合法。
而对于状态 f [ p o s ] [ i ] [ j ] [ k ] f[pos][i][j][k] f[pos][i][j][k],它能更新到的状态也就是 f [ p o s + 1 ] [ p o s + 1 ] [ j ] [ k ] f[pos+1][pos+1][j][k] f[pos+1][pos+1][j][k], f [ p o s + 1 ] [ i ] [ p o s + 1 ] [ k ] f[pos+1][i][pos+1][k] f[pos+1][i][pos+1][k], f [ p o s + 1 ] [ i ] [ j ] [ p o s + 1 ] f[pos+1][i][j][pos+1] f[pos+1][i][j][pos+1],在 d p dp dp 的时候更新即可。
这个时候,其实不难发现, p o s = m a x ( i , j , k ) pos=max(i,j,k) pos=max(i,j,k),因此可以把四维降到三维,记录 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 就行了。
【代码】
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define N 305
#define Mod 1000000007
using namespace std;
int f[N][N][N];
vector<pair<int,int> >a[N];
bool check(int x,int y,int z)
{
int i,p=max(x,max(y,z));
for(i=0;i<a[p].size();++i)
{
int num=0;
int l=a[p][i].first;
int v=a[p][i].second;
if(x>=l) num++;
if(y>=l) num++;
if(z>=l) num++;
if(num!=v) return false;
}
return true;
}
int main()
{
int n,m,i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
a[r].push_back(make_pair(l,v));
}
int ans=0;
f[0][0][0]=1;
for(i=0;i<=n;++i)
for(j=0;j<=n;++j)
for(k=0;k<=n;++k)
{
if(!f[i][j][k]) continue;
if(!check(i,j,k)) {f[i][j][k]=0;continue;}
int p=max(i,max(j,k));
if(p==n) ans=(ans+f[i][j][k])%Mod;
f[p+1][j][k]=(f[p+1][j][k]+f[i][j][k])%Mod;
f[i][p+1][k]=(f[i][p+1][k]+f[i][j][k])%Mod;
f[i][j][p+1]=(f[i][j][p+1]+f[i][j][k])%Mod;
}
printf("%d",ans);
return 0;
}