1. 程式人生 > >ACM-ICPC 2017 Asia Xi'an——LOL(DP)

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