本文主要是介绍LOL UVALive - 8521 —— 状压DP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
This way
题意:
现在有100个英雄,有5个人打人机正在进行办选局,5个人拥有的英雄都以01的方式告诉你,每个人的办选不同视为不同情况,也就是说玩家1选了德莱文和玩家二选了德莱文是两种情况,玩家1选a办b和选a办c是两种情况,但是电脑无视顺序,问你有多少种办选的情况。
题解:
这道题过了好多人。。本来是不想写题解来着,但是状压DP的话还是有写一写的价值的。
因为玩家办人是按照排列情况数来的,所以可以直接用 A 95 5 A^5_{95} A955,电脑办选是组合数,所以直接就是 C 90 5 ∗ C 85 5 C^5_{90}*C^5_{85} C905∗C855,那么剩下的就是玩家选人的方案数,因为一种状态是人,一种状态是英雄,所以应该至少需要两维来做,那么每个玩家都是不同的,这就意味着要把玩家的状态记录下来,所以现在就有一种想法:开5维。但是感觉写起来也麻烦啊,那么还有一种方法:状压人的状态:01001表示第2个和第5个人选择了英雄的情况。那么状态转移方程就非常好写了:有两种情况:
第一个是从少一个人的状态转移过来:
if((j&(1<<k))&&a[k][i])dp[i][j]=(dp[i][j]+dp[i-1][j^(1<<k)])%mod;
第二个是没有任何人选这个英雄:
dp[i][j]=(dp[i][j]+dp[i-1][j])%mod;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int a[5][105];
ll dp[105][(1<<5)+5];
ll qpow(ll a,ll b)
{ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;
}
int main()
{while(~scanf("%1d",&a[0][1])){for(int i=2;i<=100;i++)scanf("%1d",&a[0][i]);for(int i=1;i<5;i++)for(int j=1;j<=100;j++)scanf("%1d",&a[i][j]);memset(dp,0,sizeof(dp));dp[0][0]=1;for(int i=1;i<=100;i++){for(int j=0;j<(1<<5);j++){for(int k=0;k<5;k++){if((j&(1<<k))&&a[k][i])dp[i][j]=(dp[i][j]+dp[i-1][j^(1<<k)])%mod;}dp[i][j]=(dp[i][j]+dp[i-1][j])%mod;}}ll ans=dp[100][(1<<5)-1];for(ll i=95;i>=91;i--)ans=ans*i%mod;for(ll i=90;i>=86;i--)ans=(ans*i%mod)*qpow(90-i+1,mod-2)%mod;for(ll i=85;i>=81;i--)ans=(ans*i%mod)*qpow(85-i+1,mod-2)%mod;printf("%lld\n",ans);}return 0;
}
这篇关于LOL UVALive - 8521 —— 状压DP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!