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<bits/stdc++.h>

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;
}

猜你喜欢

转载自blog.csdn.net/wookaikaiko/article/details/79762818