LOL UVALive - 8521

#include <bits/stdc++.h>
using namespace std;
/*
题意有点模糊不全,敌方选人如何选不知道
我们假设敌方选人和我方选人一样,选的顺序不一样,即使选的英雄一样也不行

禁英雄,只要禁的一样,那么就说是同一种情况
那么此题就转成排列组合

我方先选出人来,然后乘A(95,5)*C(90,5)*C(85,5)

如何计算我放选人的组合数
状压dp
dp[i][j]表示选到第i个英雄,我方五人是否选人的情况为j时排列组合数
j转换成二进制来表示五人的选人情况,1代表选人了,0代表没选

两种情况
选这个英雄
if(j&1<<k&&s[k][i])
dp[i][j]=max(dp[i][j],dp[i-1][j^(1<<k)]+dp[i][j])%mod;

不选
dp[i][j]=max(dp[i][j],dp[i][j]+dp[i-1][j])%mod;

*/
typedef long long ll;
const int maxn=109;
ll dp[maxn][(1<<5)+10];
int s[6][maxn];
ll mod=1000000007;
ll A(ll n,ll m)
{
    ll sum=1;
    for(ll i=n; i>n-m; i--)
        sum=sum*i;
    return sum;
}
ll C(ll n,ll m)
{
    ll sum=1;
    for(ll i=1; i<=m; i++)
        sum=sum*(n-i+1)/i;
    return sum;
}
int main()
{
    //多组样例输入呀
    while(~scanf("%1d",&s[1][1]))
    {  for(int j=2;j<=100;j++)scanf("%1d",&s[1][j]);
        for(int i=2; i<=5; i++)
            for(int j=1; j<=100; j++)
                scanf("%1d",&s[i][j]);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<5;i++)
            if(s[i+1][1])dp[1][1<<i]=1;
        dp[1][0]=1;
        //dp[0][0]=1;//两种方式都可以
        for(int i=2; i<=100; i++)
            for(int j=0; j<(1<<5); j++)
            {
                for(int k=0; k<5; k++)
                {
                    if((j&(1<<k))&&s[k+1][i])
                        dp[i][j]=(dp[i-1][j^(1<<k)]+dp[i][j])%mod;
                }
                dp[i][j]=(dp[i][j]+dp[i-1][j])%mod;
            }
        ll ans=dp[100][(1<<5)-1];
        ans=(ans*A(95,5))%mod*((C(90,5)%mod*C(85,5))%mod);
        printf("%lld\n",ans%mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhangzhenjun/p/11779248.html
今日推荐