ZOJ - 3747 Attack on Titans

算法竞赛:求特定条件下的排列总数
本文介绍了一个算法竞赛题目,通过动态规划解决在给定条件下求解士兵排列总数的问题。具体条件包括至少m个连续的G士兵和最多k个连续的R士兵。文章提供了详细的代码实现和思路解析。

题意就是输入三个数字 n m k,  给n个士兵排队

每个士兵三种G,R,P可选,求至少有m个连续的G士兵和最多有k个连续的R士兵的排列总和

 

分析题意:在n个士兵中至少有m个连续的G士兵和最多有k个连续的R士兵的排列总和

就等于 (在n个士兵中最多有k个连续的R士兵和最多有n个连续的G士兵) - (在n个士兵中最多有k个连续的R士兵和最多有m-1个连续的G士兵)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#include<cmath>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
using namespace std;

#define Maxn 1100000

LL dp[Maxn][5]; //dp[i][0]表示第i个为G,至多有u个连续G,至多有v个连续R的个数
                //dp[i][1]表示第i个为R,....
                //dp[i][2]表示第i个为P,....
LL n,m,k,u,v;

LL Cal()
{
    dp[0][0]=1; //初始状态
    dp[0][1]=0;
    dp[0][2]=0;

    for(int i=1;i<=n;i++)
    {
       LL sum=(dp[i-1][0]+dp[i-1][1]+dp[i-1][2])%M;
       dp[i][2]=sum;

       if(i<=u)
            dp[i][0]=sum;
       else if(i==u+1)
            dp[i][0]=(sum-1)%M;
       else
            dp[i][0]=(sum-dp[i-u-1][1]-dp[i-u-1][2])%M;

       if(i<=v)
            dp[i][1]=sum;
       else if(i==v+1)
            dp[i][1]=(sum-1)%M;
       else
            dp[i][1]=(sum-dp[i-v-1][0]-dp[i-v-1][2])%M;

       //printf("u:%lld v:%lld i:%d %lld %lld %lld\n",u,v,i,dp[i][0],dp[i][1],dp[i][2]);
       //system("pause");

    }
    return (dp[n][0]+dp[n][1]+dp[n][2])%M;
}


int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   while(~scanf("%lld%lld%lld",&n,&m,&k))
   {
       LL ans;
       u=n,v=k;
       ans=Cal();

       //printf(":%lld\n",ans);
       //system("pause");

       u=m-1,v=k;
       //printf(":%lld\n",Cal());
       //system("pause");
       ans=((ans-Cal())%M+M)%M;
       printf("%lld\n",ans);


   }
   return 0;
}

 

转载于:https://www.cnblogs.com/tonyyy/p/10432896.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值