【第一届文翁杯现场竞技赛T1】洗刷刷

【题目】

传送门

题目描述:

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(1n,m300)

接下来是 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(1lirin,1vi3)

输出格式:

输出一个整数表示方案数,对 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值