画积木
推导见上图
因为画布为2*n
,只有两行,所以可以考虑每一种占满两行的方式,对每种方式做一个状态转移,得到的就是总方案数。
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+100;
const int mod=1e9+7;
typedef long long ll;
ll f[N],sum[N];
ll n;
int main(){
cin>>n;
f[0]=1;f[1]=1;f[2]=2;
sum[0]=1;sum[1]=2;sum[2]=4;
for(int i=3;i<=n;i++){
f[i]=(f[i]+f[i-1])%mod;
f[i]=(f[i]+f[i-2])%mod;
// for(int j=i-3;j>=0;j--){
// f[i]=(f[i]+f[j])%mod;
// f[i]=(f[i]*2)%mod;
// }
f[i]=(f[i]+sum[i-3]+sum[i-3])%mod;
sum[i]=(sum[i-1]+f[i])%mod;
}
cout<<f[n];
return 0;
}
李白打酒加强版
同上也是一个算方案数的dp。
首先得想到:如果酒的数量比剩下的花的数量还多,那多的酒可以忽略不计
因为每次看见花才喝一壶,那酒大于花,做差剩下的永远也喝不完。
dp[i][j][k]
表示走了i次,经过了j个花,还剩下k斗酒。
初始状态 dp[0][0][2]=1
计数dp
终止状态 dp[n+m-1][m-1][1]
表示李白差一次走完所有店和花了,走了m-1个花,最后一个是花,最后还剩一斗酒,最后看见花的时候喝。
中间要讨论奇偶性,因为在k为奇数时是不可能是店的,因为店是翻倍,得到的k一定是一个偶数。
在偶数时则是都可以转移,所以在奇数时转移当前为花店,在偶数时转移当前为花店或酒店的情况。
#include<bits/stdc++.h>
using namespace std;
const int N=210;
const int mod=1e9+7;
typedef long long ll;
ll n,m;
ll dp[N][N][N];
int main(){
cin>>n>>m;
dp[0][0][2]=1;
for(int i=1;i<=n+m-1;i++){
for(int j=0;j<=m-1;j++){
for(int k=0;k<=m;k++){
if(k%2==0){
dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k>>1])%mod;
}
if(j>=1){
dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k+1])%mod;
}
}
}
}
cout<<dp[n+m-1][m-1][1]<<endl;
return 0;
}