题意:
这是个2048游戏的简化版,只有一行,如果有两个位置的值相等那么就相加,知道不能加为止,题目给出n个数只有三种情况0、2、4, 0表示可以是2也可以是4。问给出的n个数中满足和大于k的方案数。
题解:
一眼看过去方程很快出来,看似很简单但是很难。因为有这样数据8422,2242222,这样的话中间有组个不能相加,那么要处理后面如果后面的加起来等于前面的于是又可以相加。看到这种数据的确想不到什么好办法。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const ll MOD=1000000007;
const int maxn=2005;
const int maxm=2050;
ll dp[maxn][maxm][2];
int a[maxn];
int main()
{
int n,k;
while(scanf("%d %d",&n,&k)!=EOF)
{
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[0][0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<maxm;j++)
{
int p;
if(a[i]==0||a[i]==2)
{
p=min(j+2,2048);
dp[i][p][0]=(dp[i][p][0]+dp[i-1][j][0]+MOD)%MOD;
dp[i][p][1]=(dp[i][p][1]+dp[i-1][j][1]+MOD)%MOD;
}
if(a[i]==0||a[i]==4)
{
if(j%4)
{
if(j>=(1<<k))///这步非常关键!!
dp[i][4][1]=(dp[i][4][1]+dp[i-1][j][0]+MOD)%MOD;
else
dp[i][4][0]=(dp[i][4][0]+dp[i-1][j][0]+MOD)%MOD;
dp[i][4][1]=(dp[i][4][1]+dp[i-1][j][1]+MOD)%MOD;
}
else
{
p=min(j+4,2048);
dp[i][p][0]=(dp[i][p][0]+dp[i-1][j][0]+MOD)%MOD;
dp[i][p][1]=(dp[i][p][1]+dp[i-1][j][1]+MOD)%MOD;
}
}
}
}
ll ans=0;
for(int i=0;i<maxm;i++)
{
ans=(ans+dp[n][i][1]+MOD)%MOD;
if(i>=(1<<k))
ans=(ans+dp[n][i][0]+MOD)%MOD;
}
cout<<ans<<endl;
}
return 0;
}
/**
0 2 2
1 0 100
1 2 0
3
*/