zoukankan      html  css  js  c++  java
  • CS Academy Distinct Neighbours(经典dp)

    CS Academy Distinct Neighbours(经典dp)

    题意:

    求相邻无相同数字的合法的排列数

    题解:

    题解

    先将相同的数字分为一类,假设共有n组
    定义(dp[i][j])表示前i组数字恰好有j对相邻数字相同的方案数,那么最后答案就是dp[n][0]

    已经考虑完了前(i)组数,现在考虑第(i+)组数,如何放置
    首先可以枚举放(k)个位置,有(C(cnt[i+1]-1,k-1))种放法,然后将这k个位置分成两类
    一类放在相同的数字中间 放了(L)个位置,有(C(j,L))种那么相邻相同的对数变成(j - L)
    一类不放相同的数字中间 放(k - L) 个位置,有(C(S - j,k - L))
    最后第(i+1)组数 增加了(cnt[i+1] - k)对相邻相同的数,即最后变成(dp[i+1][j - L + cnt[i+1] - k])

    四层循环 复杂度(O(n^{3}))

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N = 800;
    const int mod = 1e9 + 7;
    int C[N][N];
    void init(){
        for(int i = 0;i < N;i++) C[i][0] = C[i][i] = 1;
        for(int i = 2;i < N;i++){
            for(int j = 1;j <= i;j++){
                C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
            }
        }
    }
    int dp[N][N],cnt[N],total[N];
    vector<int> v;
    int main(){
    
        init();
        int n,x,mx = 1;
        cin>>n;
        v.push_back(0);
        for(int i = 1;i <= n;i++){
            cin>>x;
            if(!cnt[x]) v.push_back(x);
            cnt[x]++;
        }
        for(int i = 1;i < v.size();i++) total[i] = total[i-1] + cnt[v[i]];
        dp[0][0] = 1;
        for(int i  = 0;i < v.size() - 1;i++){
            int num = cnt[v[i+1]],S = total[i]+1;
            for(int j = S-1;j >= 0;j--){///j对不同
                int kk = min(num,S);///kk个位置可选择
                for(int k = 1;k <= kk;k++){
                    int L = min(j,k);
                    for(int l = L;S - j >= k - l;l--){
                        int &res = dp[i+1][j - l + num - k];
                        res = (res + 1LL * C[num - 1][k - 1] * C[j][l] % mod * C[S-j][k-l]%mod * dp[i][j]%mod)%mod;
                    }
                }
            }
        }
        cout<<dp[v.size()-1][0]<<endl;
        return 0;
    }
    
    

    听说还有(O(n^{2}))的做法 用到了下面这个东西,研究一下再写写

    (n_1)(a_1),(n_2)(a_2),...(n_r)(a_r)的相邻无相同的排列方法数

    [f(n_1,n_2,...,n_r) = sum_{1<=t_i<=n_i}^{r}coprod_{i=1}^{r}(-1)^{n_i-t_i}inom{n_i-1}{t_i-1}frac{(t_1+t_2+...+t_r)!}{t_1!t_2!...t_r!} ]

  • 相关阅读:
    从字符串中找到中文
    Extjs前端细节处理
    《高效能人士的7个习惯》读后摘记
    千分位设置
    Java语言程序设计 上机实验2 掌握Java的基本语言成分和流程控制语句。 掌握Java中数组的使用,理解引用数据类型。 掌握String类的使用。
    java报告(一)编程打印一个三角形的乘法口诀表
    计算机组成原理 课程设计报告
    汇编语言作业(七)
    汇编语言作业(六)
    汇编语言作业(五)
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7410938.html
Copyright © 2011-2022 走看看