zoukankan      html  css  js  c++  java
  • LOL 计蒜客

    给出5个长度为100的字符串
    1表示有这个英雄,0表示没有
    传送门

    相当于就是5*100的矩阵,要求每一行选择一个下标且权值是1,且都不在同一列.
    表示我方pick的情况,最后在剩下的那一部分,C(95,5)表示我方的部分
    C(90,5)表示敌方ban的部分,C(85,5)表示敌方pick的部分,然后敌方是必须进行全排列的.

    想法就是先去选择好我方pick部分,然后ban的部分只能在没有选择的部分里面,这样就不会冲突了,因为一般来说我ban必须在pick之前进行的.

    那么设(dp[i][j])表示当选择第(i - 1)个英雄时, 选择情为j的情况.进行状压,只有(5)个人,那么就是(1<<5)
    (int dp[105][1 << 5];)

    状态转移方程就是
    dp[i][j]的转移就是我第i个英雄不选,直接继承dp[i - 1][j]的情况.
    第i个英雄选择,继承dp[i - 1][j ^ (1 << k)]表示继承于之前的不含有为当前状态的情况.
    答案就是(dp[100][1 << 5 - 1])
    (1 << 5 - 1)就是5个都选择的情况.
    时间复杂度(O(n2^k))

    其实也可以直接暴力,就是遍历4个for循环遍历每个人都pick了哪个英雄,然后第5个人就看看还剩下哪些英雄可以选择就可以了,时间复杂的(O(1e8))了,数据太水,可以过.

    #include <bits/stdc++.h>
    #define ll long long
    #define ld long double
    #define CASE int Kase = 0; cin >> Kase; for(int kase = 1; kase <= Kase; kase++)
    using namespace std;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    #ifdef ONLINE_JUDGE
    #define qaq(...) ;
    #define qwq(c) ;
    #else
    #define qwq(a, b) for_each(a, b, [=](int x){cerr << x << " ";}), cerr << std::endl
    template <typename... T> void qaq(const T &...args) {
        auto &os = std::cerr;
        (void)(int[]){(os << args << " ", 0)...};
        os << std::endl;
    }
    #endif
    const int N = 2e5 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f; const ll linf = 0x7f7f7f7f7f7f7f7f;
    int dp[105][1 << 5]; // 选择第i - 1个英雄时, 选择情况为j
    ll C[105][105], fac[105];
    string s[6];
    ll pow(ll a, ll b, ll p){
        ll ans = 1;
        while(b) {
            if(b & 1) ans = ans * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ans;
    }
    ll inv(ll a, ll p){
        return pow(a, p - 2, p);
    }
    ll A(ll n, ll m){
        if(n < m) return 0;
        return fac[n] * inv(fac[n - m], MOD) % MOD;
    }
    void solve(int kase){
        fac[0] = 1;
        for(int i = 1; i <= 100; i++) fac[i] = fac[i - 1] * i % MOD;
        C[0][0] = 1;
        for(int i = 1; i <= 100; 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;
            }
        }
        while(cin >> s[0]) {
            for(int i = 1; i < 5; i++) cin >> s[i];
            memset(dp, 0, sizeof(dp));
            dp[0][0] = 1;
            for(int i = 1; i <= 100; i++){
                for(int j = 0; j < (1 << 5); j++) dp[i][j] = dp[i - 1][j];// 当前所有物品都不选的情况
                for(int j = 0; j < (1 << 5); j++){
                    for(int k = 0; k < 5; k++){
                        if((j & (1 << k)) && (s[k][i - 1] == '1')){ // 当第i - 1个英雄被k pick时
                            dp[i][j] = (dp[i][j] + dp[i - 1][j ^ (1 << k)]) % MOD; // 选择这个物品,继承于之前的不含有为当前状态的情况
                        }
                    }
                }
            }
            ll ans = dp[100][(1 << 5) - 1];
            printf("%lld
    ", A(95, 5) * C[90][5] % MOD * C[85][5] % MOD * ans % MOD);
        }
    }
    const bool ISFILE = 0, DUO = 0;
    int main(){
        clock_t start, finish; start = clock();
        if(ISFILE) freopen("/Users/i/Desktop/practice/in.txt", "r", stdin);
        if(DUO) {CASE solve(kase);} else solve(1);
        finish = clock(); 
        qaq("
    Time:", (double)(finish - start) / CLOCKS_PER_SEC * 1000, "ms
    ");
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    java9
    java8
    java7
    java6
    java5
    java4
    java-list-分组
    Termux中安装gcc-7/gfortran-7实操过程,安装成功可以编译Fortran,c/c++
    安卓手机牛逼软件Termux中安装Archlinux,安装Jdk
    c++语言的组合类的使用,用组合类的方法计算两点间距离。
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14694214.html
Copyright © 2011-2022 走看看