AtCoder Grand Contest 013 D - Piling Up 动态规划

题意

有一个盒子里面有n个球,每个球是红色或蓝色。现在要进行m轮操作,每轮操作如下:
随意从盒子里拿一个球
放一个红球和一个蓝球进盒子
随意从盒子里拿一个球
问有多少种可能的不同的拿球序列。
n,m<=3000

分析

很直观的想法是设f[i,j]表示进行完了第i轮,有当前盒子里有j个红球的方案。转移的话考虑这一轮拿的情况就好了。
不难发现这样会算重,就是一种拿球序列可能会由多种初始情况转移过来。
想要不重不漏地计数的话,就要让一种拿球序列由唯一的一种初始情况转移过来,我们可以选择让初始红球数量最少的状态来转移,这样的话就必然有某个时刻满足红球数量为0。
这样的话我们可以多加一维,设f[i,j,0/1]表示是否在某个时刻红球数量为0即刻。

代码

#include
#include
#include
#include
#include
using namespace std;

const int N=3005;
const int MOD=1000000007;

int n,m,f[N][N][2];

void updata(int &x,int y)
{
    x+=y;x-=x>=MOD?MOD:0;
}

int main()
{
    scanf("%d%d",&n,&m);
    f[0][0][1]=1;
    for (int i=1;i<=n;i++) f[0][i][0]=1;
    for (int i=0;ifor (int j=0;j<=n;j++)
            for (int k=0;k<=1;k++)
            {
                if (j) updata(f[i+1][j-1][k|(j==1)],f[i][j][k]);
                if (j) updata(f[i+1][j][k|(j==1)],f[i][j][k]);
                if (n-j) updata(f[i+1][j+1][k],f[i][j][k]);
                if (n-j) updata(f[i+1][j][k],f[i][j][k]);
            }
    int ans=0;
    for (int i=0;i<=n;i++) updata(ans,f[m][i][1]);
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(动态规划)