AtCoder Grand Contest 013D: Piling Up 题解
2017-10-03 23:14
459 查看
非常难的dp
容易想到状态dp[i][j]表示当前进行了i轮操作,第i轮操作结束后盒子里有j个红球的方案数,因为盒子里始终有N个球,所以蓝球的个数为N-j,于是可以转移
但这样有些状态会重复计数
例如:设N=2,则开始状态是Red=2,Blue=0时,可以获得“取出序列”Red,Blue,Red,Blue...
当开始状态是Red=1,Blue=1时,也可以获得“取出序列”Red,Blue,Red,Blue...
我们发现:同一个“取出序列”可以对应多种初始状态,所以有些“取出序列”会被重复计算
一个很好的比喻是,如果将这个“取出序列”在坐标系中化成一条折线,横坐标表示取到第几轮,纵坐标表示盒子里有几个红球
那么同样形状的折线对应的应该是同一种“取出序列”,然而由于折线的出发点不同,即刚开始红球的数量不确定,所以从每个点出发都会有这样一条折线
于是对于同样形状的曲线,我们考虑取其中最特殊的一条:初始状态中红球数最小的一条,即在坐标系中出发点最低的一条
最低的一条应该满足存在一个时刻,红球的数量为0,否则如果红球数量一直大于零,初始状态中的红球一定可以再减少
如下图,两条曲线代表同样的答案被计算多次,我们只计与x轴“相切”的那条
于是有新状态dp[i][j][0/1],第三维为0表示这个序列已经在之前(包括现在)的某时刻红球数为0,第三维为1反之亦然
我们有了正确的状态,但转移也非常难写
一方面要考虑到j=0,j=1,j=n的边界条件
另一方面,红红,红蓝,蓝红,蓝蓝四种转移方法,注意在红蓝和蓝红这两种转移方法中,在转移中间(即拿完红球还没补球时)红球数为0也算与x轴相切
容易想到状态dp[i][j]表示当前进行了i轮操作,第i轮操作结束后盒子里有j个红球的方案数,因为盒子里始终有N个球,所以蓝球的个数为N-j,于是可以转移
但这样有些状态会重复计数
例如:设N=2,则开始状态是Red=2,Blue=0时,可以获得“取出序列”Red,Blue,Red,Blue...
当开始状态是Red=1,Blue=1时,也可以获得“取出序列”Red,Blue,Red,Blue...
我们发现:同一个“取出序列”可以对应多种初始状态,所以有些“取出序列”会被重复计算
一个很好的比喻是,如果将这个“取出序列”在坐标系中化成一条折线,横坐标表示取到第几轮,纵坐标表示盒子里有几个红球
那么同样形状的折线对应的应该是同一种“取出序列”,然而由于折线的出发点不同,即刚开始红球的数量不确定,所以从每个点出发都会有这样一条折线
于是对于同样形状的曲线,我们考虑取其中最特殊的一条:初始状态中红球数最小的一条,即在坐标系中出发点最低的一条
最低的一条应该满足存在一个时刻,红球的数量为0,否则如果红球数量一直大于零,初始状态中的红球一定可以再减少
如下图,两条曲线代表同样的答案被计算多次,我们只计与x轴“相切”的那条
于是有新状态dp[i][j][0/1],第三维为0表示这个序列已经在之前(包括现在)的某时刻红球数为0,第三维为1反之亦然
我们有了正确的状态,但转移也非常难写
一方面要考虑到j=0,j=1,j=n的边界条件
另一方面,红红,红蓝,蓝红,蓝蓝四种转移方法,注意在红蓝和蓝红这两种转移方法中,在转移中间(即拿完红球还没补球时)红球数为0也算与x轴相切
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <algorithm> #include <cstdlib> #include <utility> #include <stack> #include <queue> #include <deque> #include <set> #include <map> #include <vector> #include <cmath> #define Pair pair<int,int> #define LOWBIT(x) x & (-x) #define LL long long #define mp make_pair #define pb push_back #define x first #define y second using namespace std; const int MOD=1e9+7; const int INF=0x7ffffff; const int magic=348; const double eps=1e-9; //ith step,j red LL dp[3048][3048][2]; int n,m; inline LL mod(LL x) { while (x>=MOD) x-=MOD; while (x<0) x+=MOD; return x; } int main () { int i,j,k; scanf("%d%d",&n,&m); dp[0][0][0]=1; for (i=1;i<=n;i++) dp[0][i][1]=1; LL ans=0; for (i=1;i<=m;i++) for (j=0;j<=n;j++) { if (j==0) { dp[i][j][0]=mod(dp[i-1][1][0]+dp[i-1][1][1]+dp[i-1][0][0]); if (i==m) ans=mod(ans+dp[i][j][0]); continue; } if (j==1) { dp[i][j][0]=mod((j+1<=n?dp[i-1][j+1][0]:0)+(j==n?dp[i-1][j][0]:2*dp[i-1][j][0])+dp[i-1][j-1][0]+dp[i-1][j][1]); if (i==m) ans=mod(ans+dp[i][j][0]); dp[i][j][1]=mod((j+1<=n?dp[i-1][j+1][1]:0)+(j==n?0:dp[i-1][j][1])); continue; } dp[i][j][0]=mod((j+1<=n?dp[i-1][j+1][0]:0)+(j==n?dp[i-1][j][0]:2*dp[i-1][j][0])+dp[i-1][j-1][0]); dp[i][j][1]=mod((j+1<=n?dp[i-1][j+1][1]:0)+(j==n?dp[i-1][j][1]:2*dp[i-1][j][1])+dp[i-1][j-1][1]); if (i==m) ans=mod(ans+dp[i][j][0]); } printf("%I64d\n",ans); return 0; }
相关文章推荐
- Atcoder Grand Contest 013 D Piling Up
- [AtCoder Grand Contest 013] D: Pilling Up (agc013d)
- AtCoder Grand Contest 013
- 【思维】AtCoder Grand Contest(013)C[Ants on a Circle]题解
- Atcoder Grand Contest 013 E Placing Squares
- Atcoder Grand Contest 013D - Piling Up
- AtCoder Grand Contest 013 题解
- AtCoder Grand Contest 013 C :Ants on a Circle
- AtCoder Grand Contest 013 C - Ants on a Circle 乱搞
- AtCoder Grand Contest 013 D - Piling Up 动态规划
- AtCoder Grand Contest 010 D - Decrementing
- AtCoder Grand Contest 016 E - Poor Turkeys 贪心
- Atcoder Grand Contest 018 D Tree and Hamilton Path
- AtCoder Grand Contest 072 E - Alice in linear land
- Atcoder Grand Contest 012 B - Splatter Painting解题报告
- Atcoder Grand Contest 022 B 题解
- AtCoder Grand Contest 018A: Getting Difference 题解
- 单挑养成计划【3】 AtCoder Grand Contest 003
- AtCoder Grand Contest 019 B - Reverse and Compare
- Atcoder Grand Contest 019