• 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!} ]

  • 相关阅读:
    用 Java 写一个折半查找?
    阐述 ArrayList、Vector、LinkedList 的存储性能和特性?
    简述一下面向对象的”六原则一法则”?
    如何通过反射调用对象的方法?
    用 Java 写一个单例类?
    事务的 ACID 是指什么?
    如何通过反射创建对象?
    如何通过反射获取和设置对象私有字段的值?
    JDBC 中如何进行事务处理?
    获得一个类的类对象有哪些方式?
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7410938.html
Copyright © 2020-2023  润新知