ACM-ICPC 2017 Asia Xi'an——LOL(DP)

题意:

模仿游戏LOL,己方选择5个英雄(能选择的前提是已经买了这个英雄)

自己这一方选的英雄肯定不能一样,敌方也选择5个英雄但是可以随便选喜欢的
然后己方和敌方可以分别各禁止5个英雄,总的英雄种类数是100个.

题解:

题意具体化到给出的输入数据来说就是给5行只由0和1组成的字符串,在每一行选择一个1,各行选的1不能在同一列。

可以用DP来做,先把第一行的可选方案处理出来,也就是第一行1的个数,然后在接下来的2~5行里面根据前面的选择选择自己的,因为列数相同选择的行数不同也算是不同的方案,所以我们对五行数进行全排列,这样就算出了己方可以选择的方案,这不算完,因为要求的大家选择的匹配方案,所以要加上敌方可选的英雄方案和大家所禁止的英雄方案用式子表示为: A(95,5)*C(90,5)*C(85,5)(式子代表:地方要在己方选择了5个人后剩下的人中选择5个,并且选择的顺序不同也算不同方案,所以用排列表示,之后两方都要选择要禁止的英雄顺序不影响所以用组合数表示)只要用己方可选的方案乘上这个数就得到了答案。

DP转移方程: dp[i][j]=dp[i][j]+dp[i-1][j-1];

题目来源于计蒜客

代码实现:

#include

using namespace std;
typedef long long ll;
const ll mod=1e9+7;
char s[6][105];
ll dp[6][105],ans;
void ini(int t)
{
    if(t==5)
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=100;i++)
        {
            dp[1][i]=dp[1][i-1];
            if(s[1][i]=='1')
                dp[1][i]++;
        }
        for(int i=2;i<=5;i++)
        {
            for(int j=1;j<=100;j++)
            {
                dp[i][j]=dp[i][j-1];
                if(s[i][j]=='1')
                    dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
            }
        }
        ans=(ans+dp[5][100])%mod;
        return ;
    }
    for(int i=t;i<=5;i++)//对行进行全排列
    {
        swap(s[i],s[t]);
        ini(t+1);
        swap(s[i],s[t]);
    }
}
int main()
{
    //ll num=531192757;
      // ll num=531192759;
      ll num=531192758;
    while(scanf("%s",s[1]+1)!=EOF)
    {
        for(int i=2;i<=5;i++)
        scanf("%s",s[i]+1);
        ans=0;
        ini(1);
        printf("%lld\n",ans*num%mod);
    }
    return 0;
}

 

你可能感兴趣的:(DP)