题目意思:
有n张牌,求出至少有k张牌连续是正面的排列的种数。
解题思路:
高精度+递推
显然n张牌总的排列数为2^n,如果减去最多有(k-1)张连续正面的情况,就是最后的结果。
dp[i][0]:表示第i张牌为正面,且最多有k张连续的正面的种数
dp[i][1]=dp[i-1][0]+dp[i-1][1];
dp[i][0] 当i<=k时,dp[i][0]=dp[i-1][0]+dp[i-1][1]
当i==k+1时,dp[i][0]=dp[i-1][0]+dp[i-1][1]-1;
当i>k+1时,dp[i][0]=dp[i-1][0]+dp[i-1][1]-dp[i-k-1][1];
代码:
#define Maxn 110
int dp[Maxn][2][Maxn];// dp[i][0]表示第i个为H,至多出现连续k个连续H,个数
int n,k;
int temp[Maxn];
int ans[Maxn];
int res[Maxn];
void add(int a[],int b[]) //加法
{
int aa=0;
memset(res,0,sizeof(res));
for(int i=100;i>=1;i--)
{
res[i]=(a[i]+b[i]+aa)%10000;
aa=(a[i]+b[i]+aa)/10000;
}
}
void sub(int a[110],int b[110]) //减法
{
int cur=0;
memset(res,0,sizeof(res));
for(int i=100;i>=1;i--)
{
if(a[i]-cur>=b[i])
{
res[i]=a[i]-cur-b[i];
cur=0;
}
else
{
res[i]=a[i]+10000-b[i]-cur;
cur=1;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&n,&k))
{
memset(dp,0,sizeof(dp));
memset(ans,0,sizeof(ans));
ans[100]=1;
dp[0][0][100]=1;
k--;
for(int i=1;i<=n;i++)
{
add(dp[i-1][0],dp[i-1][1]);
memcpy(dp[i][1],res,sizeof(res));
if(i<=k)
{
add(dp[i-1][0],dp[i-1][1]);
memcpy(dp[i][0],res,sizeof(res));
}
else if(i==k+1)
{
memset(temp,0,sizeof(temp));
temp[100]=1;
add(dp[i-1][0],dp[i-1][1]);
memcpy(dp[i][0],res,sizeof(res));
sub(dp[i][0],temp);
memcpy(dp[i][0],res,sizeof(res));
}
else
{
add(dp[i-1][0],dp[i-1][1]);
memcpy(dp[i][0],res,sizeof(res));
sub(dp[i][0],dp[i-k-1][1]);
memcpy(dp[i][0],res,sizeof(res));
}
add(ans,ans);
memcpy(ans,res,sizeof(res));
int j=1;
while(!ans[j]&&j<=100)
j++;
}
sub(ans,dp[n][0]);
memcpy(ans,res,sizeof(res));
sub(ans,dp[n][1]);
memcpy(ans,res,sizeof(res));
int i=1;
while(!ans[i]&&i<=100)
i++;
printf("%d",ans[i++]);
while(i<=100)
printf("%04d",ans[i++]);
putchar('\n');
}
return 0;