【AGC013D】Pilling Up dp

Description

红蓝球各无限多个.
初始时随意地从中选择 n 个, 扔入箱子
初始有一个空的序列
接下来依次做 m 组操作, 每组操作为依次执行下述三个步骤
(1) 从箱子中取出一个求插入序列尾
(2) 往箱子里补充 一红一蓝
(3) 从箱子中取出一个求插入序列尾
求 mm 次操作后, 有多少种不同的颜色序列, 答案对 109+7 取模

Input

第一行两个数 n,mn,m .

Output

一个数 ans 表示答案对 10^9+7 取模的值.

Sample Input

# 样例输入1

2 3

# 样例输入2

1000 10

# 样例输入3

1000 3000

Sample Output

# 样例输出1

56

# 样例输出2

1048576

# 样例输出3

693347555

HINT

样例解释1
一共有 6 个球会被从盒子中取出.
一个方案是不合法的当且仅当第 2,3,4,5 个球的颜色完全相同.

所以答案为 26−23=56

数据范围

n,m≤3000

Sol

定义(f[i][j])为进行i轮,红球j个的方案数,然后跑普及组dp,但是这样会重复,原因:一个最终序列可能是由多个初始集合生成的。但是我们发现,如果开始有i个红球能够生成一个序列,i+j个也可以,那么我们找到这个最小的i,可以发现一定会用完,所以再加一维([0/1])表示有没有用完过红球,然后就不会有重复了。

Code

#include <cstdio>
int n,m,f[3005][3005][2],ans;const int P=1e9+7;
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;i<m;i++) for(int j=0;j<=n;j++) for(int k=0;k<=1;k++)
    {
        if(j) f[i+1][j-1][k|!(j-1)]=(f[i+1][j-1][k|(j==1)]+f[i][j][k])%P;
        if(n-j) f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k])%P;
        if(j) f[i+1][j][k|(j==1)]=(f[i+1][j][k|(j==1)]+f[i][j][k])%P;
        if(n-j) f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%P;
    }
    for(int i=0;i<=n;i++) ans=(ans+f[m][i][1])%P;
    printf("%d
",ans);
}

原文地址:https://www.cnblogs.com/CK6100LGEV2/p/9469383.html