【agc013d】Piling Up(动态规划)

本文解析AtCoder题目PilingUp,利用动态规划求解球的序列方案数。通过调整操作理解,引入状态转移方程,强制在特定状态计算答案,最终求得所有可能方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【agc013d】Piling Up(动态规划)

题面

atcoder
洛谷
\(n\)个球,颜色为黑白中的一种,初始时颜色任意。
进行\(m\)次操作,每次操作都是先拿出一个求,再放进黑白各一个,再拿出一个球。
求最终拿出球的序列的方案数。

题解

首先可以把操作看成每次拿出一个球把它染上任意一种颜色。
\(f[i][j]\)表示进行完前\(i\)次操作,还剩下\(j\)个黑球的方案数。
拿出球的序列如果只从黑球的角度来看的话,可以看成一个\(+1,-1\)组成的折线。
如果折线能够到达的最小值不为\(0\),那么我们可以通过平移把它移到\(0\)这个位置,并且平移过程中所有的操作序列所得到的结果串都是一样的。
那么我们强制只在\(0\)位置计算答案,给状态额外加上一维,表示\(j\)是否到达过\(0\)
这样子答案就是\(\sum f[m][j][1]\)了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 3030
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int n,m,ans,f[MAX][MAX][2];
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=1;i<=m;++i)
        for(int j=0;j<=n;++j)
            for(int k=0;k<=1;++k)
            {
                if(j)add(f[i][j][k|(j==1)],f[i-1][j][k]),add(f[i][j-1][k|(j==1)],f[i-1][j][k]);
                if(n-j)add(f[i][j+1][k],f[i-1][j][k]),add(f[i][j][k],f[i-1][j][k]);
            }
    for(int i=0;i<=n;++i)add(ans,f[m][i][1]);
    printf("%d\n",ans);return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/10468305.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值