zoukankan      html  css  js  c++  java
  • 组合数+动态规划

    1:求相同班级的学生不相邻的全排列

    f[i][j]代表已经处理完了前i个班级,有多少个空隙左边和右边的同学的班级相同。

    我们考虑把第i个班级的同学分成k组,然后有u组分在了左边和右边相同的空隙中,其他的分在了左边和右边不相同的空隙中。

    首先把把a[i]个学生分成k组,所以这个分法一共有C[a[i]-1][k-1];

    然后把这k组同学分成u组,所以一共的分法是C[k][u];//这个东西是不能加的,想一下小球的问题就行了。

    然后我把这u组放在j个空隙中,所有的可能性 C[j][u];

    然后我把剩下的k-u组放在剩下的空隙中所有的可能性C[sum+1-j][k-u];

    所以这个时候剩下的使左边和右边相同的空隙 j-u+b[i]-k;这个画个图就能很好的看出来了。

    然后最后的结果就是f[n][0]然后在让所有的同学不同就行了,然后就是乘每个班级人数的全排列就行了。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int MOD=1e9+7;
    long long C[699][600];
    long long dp[50][500];
    long long fac[600];
    int a[600];
    void inist()
    {
        memset(C,0,sizeof(C));
        for(int i=0;i<=500;i++)
        {
            C[i][0]=1;
            for(int j=1;j<=i;j++)
            {
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
            }
        }
        fac[0]=1;
        for(int i=1;i<=500;i++) fac[i]=fac[i-1]*i%MOD;
    }
    int main()
    {
        inist();
        int t,n;
        scanf("%d",&t);
        int id=0;
        while(t--)
        {
            id++;
            memset(dp,0,sizeof(dp));
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            dp[1][a[1]-1]=1;
           // sum=a[1];
            int sum=0;
            for(int i=2;i<=n;i++)
            {
                sum+=a[i-1];
                for(int j=0;j<sum;j++)
                {
                    if(!dp[i-1][j]) continue;
                    for(int k=1;k<=a[i];k++)
                    {
                        for(int u=0;u<=k&&u<=j;u++)
                        {
                            long long temp=dp[i-1][j]%MOD;
                            temp=temp*C[a[i]-1][k-1]%MOD;
                            //temp*=C[k][u]%MOD; 想一下小球放在盒子里
                            temp=temp*C[j][u]%MOD;
                            temp=temp*C[sum+1-j][k-u]%MOD;
                            dp[i][j-u+a[i]-k]=(dp[i][j-u+a[i]-k]+temp)%MOD;
                        }
                    }
                }
            }
            long long ans=dp[n][0];
    
            for(int i=1;i<=n;i++)
            {
                ans=ans*fac[a[i]]%MOD;
            }
            printf("Case %d: ",id);
            printf("%lld
    ",(ans%MOD+MOD)%MOD);
        }
    }
    

      

  • 相关阅读:
    [WM]谁抢走了应用程序的性能?
    只有更烂的程序员
    [WM]n久以前写的ConnMgr类
    [WM][转]PPC中如何找到正在使用中的网络(源代码)
    让IE6支持minwidth和maxwidth的方法(JS实现) + (CSS实现)
    jQuery tab 切换函数
    wap、3g手机的端的网页头部
    复制到系统剪贴板之IE,ff兼容版
    鼠标滑过展开,js版和jquery版
    JS+CSS实现网页滚动条美化
  • 原文地址:https://www.cnblogs.com/Heilce/p/7406040.html
Copyright © 2011-2022 走看看