Atcoder [ARC074C] RGB Sequence

Description

丰泽爷今天也在愉快地玩Minecraft!

现在丰泽爷有一块1∗N的空地,每个格子按照顺序标记为1到N。丰泽爷想要在这块空地上铺上红石块、绿宝石块和钻石块作为装饰。每个格子只能选择一种方块。

丰泽爷有自己的审美标准。他定下了M条规定,每条规定形如(li,ri,xi),表示闭区间[li,ri]中,需要有恰好xi种不同的方块。

丰泽爷觉得这个任务实在是太简单了,于是把它交给了你,但是你发现有太多种方式可以满足丰泽爷的审美需求了!于是你希望先知道,一共有多少铺方块的方法,可以满足丰泽爷的审美需求?答案对109+7取模


Input

    第一行两个整数,N,M

    接下来M行,每行三个整数li,ri,xi

Output

    一个整数,对109+7取模后的答案

Solution

比较神奇的状态设计。

设dp[i][j][k]为枚举到第i个格子,离i次远的颜色不同于i的格子为j(j<i),离i最远的颜色不同于i,j的格子为k的方案数。

那么转移就很显然了。
{ d p [ i + 1 ] [ j ] [ k ] + = d p [ i ] [ j ] [ k ] d p [ i + 1 ] [ i ] [ k ] + = d p [ i ] [ j ] [ k ] d p [ i + 1 ] [ i ] [ j ] + = d p [ i ] [ j ] [ k ] \begin{cases} dp[i+1][j][k]+=dp[i][j][k]\\ dp[i+1][i][k]+=dp[i][j][k]\\ dp[i+1][i][j]+=dp[i][j][k]\\ \end{cases} dp[i+1][j][k]+=dp[i][j][k]dp[i+1][i][k]+=dp[i][j][k]dp[i+1][i][j]+=dp[i][j][k]
第一行是i+1取跟i一样的颜色。
第二行是i+1取跟j一样的颜色。
第二行是i+1取跟k一样的颜色。
这里用了ctrl+cv

再考虑l,r的限制,对于 r x = i r_x=i rx=i的情况,直接把不可行的情况置为0。
随便想想就知道怎么搞了。

最后乘个3,因为起始颜色不固定,或者把dp[1][0][0]直接设为3。


Code

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
const int mod=1e9+7;
int f[310][310][310],n,m;
vector< pair<int,int> >v[310];
int main(){
	int l,r,x;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&l,&r,&x);
        v[r].pb(mp(l,x));
    }
    f[1][0][0]=1;
    for(int i=1;i<=n;i++){
    	for(int d=0,sz=v[i].size();d<sz;d++){
        	int l=v[i][d].first,x=v[i][d].second;
        	for(int j=0;j<i;j++)
        	for(int k=0;k<=max(0,j-1);k++){
        	    if(x==1&&l<=j) f[i][j][k]=0;
            	if(x==2&&(l<=k||j<l)) f[i][j][k]=0;
            	if(x==3&&k<l) f[i][j][k]=0;
        	}
		}
        if(i==n) break;
        for(int j=0;j<i;j++)
        for(int k=0;k<=max(0,j-1);k++)
        if(f[i][j][k]){
            f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;    
            f[i+1][i][k]=(f[i+1][i][k]+f[i][j][k])%mod;
            f[i+1][i][j]=(f[i+1][i][j]+f[i][j][k])%mod;
        }
    }
    int ans=0;
    for(int j=0;j<n;j++)
    for(int k=0;k<=max(0,j-1);k++)
    ans=(ans+f[n][j][k])%mod;
    ans=(ans*3ll)%mod;
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值