您的位置:首页 > 其它

Atcoder Grand Contest 013 D Piling Up

2018-02-26 21:58 381 查看

Piling Up

Problem Statement

在箱子里放nn 个球,有黑白两种颜色。

接下来依次执行mm 轮操作,每轮操作分成三步:

1、抓箱子里一个球堆在塔顶。

2、往箱子里放入一个黑球和一个白球。

2、再抓箱子里的一个球堆在塔顶。

求不同塔的方案数(两个塔不同当前仅当存在一个位置球的颜色不同)。

Data Constraint

11≤nn≤30003000

11≤mm≤30003000

Solution

首先一轮操作的前后球的总数一定是nn。

先给出一个错误的dpdp。

设fi,xfi,x 表示执行完了前ii轮,箱子里黑球的数量为xx的,堆出的塔的不同的方案数。

转移的话就是枚举两次拿出的球的颜色的所有可能性然后进行转移。

但这样显然会算重。

考虑如何改进dpdp使得它变正确。

考虑一下为什么会算重。

如果从头到尾黑球的数量没有到达过00,那么把多余的黑球全部换成白球后,这样的方案堆出来 的塔是一样的,因此这样做会算重。

根据上述内容我们可以得到启发,设fi,x,0/1fi,x,0/1 表示执行完了前i轮,箱子里黑球的数量为xx,黑球的数 量在前ii轮中是否到达过00,最后只能选择黑球数量到达过00的ff 统计到答案中去。

这样便能做到不重不漏。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)

using namespace std;
typedef long long ll;
const ll N=32e2,mo=1e9+7;

ll f[2]
[2];

int n,m;

int main()
{
cin>>n>>m;
fo(i,1,n)f[0][i][0]=1;
f[0][0][1]=1;
int u=0,v;
fo(i,1,m){
v=u^1;
fo(i,0,n)f[v][i][0]=f[v][i][1]=0;
fo(i,0,n)f[u][i][0]=f[u][i][0]%mo,f[u][i][1]=f[u][i][1]%mo;
fo(i,1,n)f[v][i-1][(i==1)]=f[v][i-1][(i==1)]+f[u][i][0],f[v][i-1][1]=f[v][i-1][1]+f[u][i][1];
fo(i,1,n)f[v][i][(i==1)]=f[v][i][(i==1)]+f[u][i][0],f[v][i][1]=f[v][i][1]+f[u][i][1];
fo(i,0,n-1)f[v][i][0]=f[v][i][0]+f[u][i][0],f[v][i][1]=f[v][i][1]+f[u][i][1];
fo(i,0,n-1)f[v][i+1][0]=f[v][i+1][0]+f[u][i][0],f[v][i+1][1]=f[v][i+1][1]+f[u][i][1];
u=v;
}
ll ans=0;
fo(i,0,n)ans=(ans+f[u][i][1])%mo;
cout<<ans;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: