2019牛客国庆集训派对day2 Circular Coloring(动态规划)

题目链接:https://ac.nowcoder.com/acm/contest/1107/D

题意:有一个由n+m个球构成的环,Bobo希望将n个球染成黑色,将m个球染成白色。Bobo用相同的颜色对相邻的球进行分组,他将着色的权重确定为组的长度的乘积。他想知道可能的颜色权重之和。答案对1e9+7取模。

解题思路:个人觉得本题难度较大。首先我们会发现,涂成黑白两色的区域的数目相同。那么我们可以定义dp【i】【j】为将j个球分成i块所有可能的乘积的和。那么状态转移方程为:

dp【i】【j】=(j-i+1)*dp【i-1】【i-1】+(j-i)*dp【i-1】【i】+。。。+2*dp【i-1】【j-2】+dp【i-1】【j-1】。然后我们可以考虑每种情况涂成黑色最小的那块的可能位置,发现一共用n+m种可能,最后就可以得到答案了。注意不要随意取模,不然可能会超时QAQ。。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+5;
int dp[maxn][maxn];
int inv[maxn];
const long long mod=1e9+7;
int main(){
    inv[1]=1;
    for(int i=2;i<=5000;i++){
        inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    }
    dp[0][0]=1;
    for(int i=1;i<=5000;i++){
        int tem1=dp[i-1][i-1];
        int tem2=1ll*dp[i-1][i-1]*(i-1)%mod;
        for(int j=i;j<=5000;j++){
            dp[i][j]=(1ll*tem1*j-tem2+mod)%mod;
            tem1=(tem1+dp[i-1][j])%mod;
            tem2=(tem2+1ll*j*dp[i-1][j])%mod;
        }
    }
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        int tem=min(n,m);
        long long ans=0;
        for(int i=1;i<=tem;i++){
            ans=(ans+1ll*dp[i][n]*dp[i][m]%mod*inv[i])%mod;
        }
        printf("%lld\n",1ll*ans*(n+m)%mod);
    }
    return 0;
}

  

2019牛客国庆集训派对day2

猜你喜欢

转载自www.cnblogs.com/Zhi-71/p/11621118.html