ACM之DP uva 10328 Coin Toss

题目意思:
有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;

猜你喜欢

转载自blog.csdn.net/qq_41243063/article/details/81383019