cf1111d 线性求逆元,组合数学,退背包法 好题!

首先是线性打表逆元 https://www.cnblogs.com/qdscwyy/p/7795368.html

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;
int cnt[N];
char s[N];
LL ans[60][60];
int F[N], Finv[N], inv[N];///F是阶层 Finv是逆元的阶层
void init(){
    inv[1] = 1;
    for(int i = 2; i < N; i++)
        inv[i] = (mod - mod/i) * 1ll * inv[mod % i] % mod;
    F[0] = Finv[0] = 1;
    for(int i = 1; i < N; i++){
        F[i] = F[i-1] * 1ll * i % mod;
        Finv[i] = Finv[i-1] * 1ll * inv[i] % mod;
    }
}
int comb(int n, int m){ /// C(n,m)
    if(m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n-m] % mod * Finv[m] % mod;
}
int id(char ch){
    if(islower(ch)) return ch - ‘a‘ + 1;
    return ch - ‘A‘ + 27;
}
int dp[N], tp[N];
void Ac(){
    int n = strlen(s+1);
    int m = n / 2;
    for(int i = 1; i <= n; ++i)
        ++cnt[id(s[i])];
    dp[0] = 1;
    for(int i = 1; i <= 52; ++i){
        if(cnt[i]){
            for(int j = m; j >= cnt[i]; --j)
                dp[j] = (dp[j] + dp[j-cnt[i]]) % mod;
        }
    }
    for(int i = 0; i <= m; ++i)
        tp[i] = dp[i];
    for(int i = 1; i <= 52; ++i){
        if(cnt[i] && cnt[i] <= m){
            for(int j = cnt[i]; j <= m; ++j){
                dp[j] = (dp[j] - dp[j-cnt[i]] + mod) % mod;
            }
            ans[i][i] = dp[m];
            for(int j = 1; j <= 52; ++j){
                if(cnt[j] && cnt[j] <= m && j != i){
                    for(int k = cnt[j]; k <= m; ++k){
                        dp[k] = (dp[k] - dp[k-cnt[j]] + mod)%mod;
                    }
                    ans[i][j] = dp[m];
                    for(int k = m; k >= cnt[j]; --k){
                        dp[k] = (dp[k] + dp[k-cnt[j]]) % mod;
                    }
                }
            }
            for(int j = m; j >= cnt[i]; --j)
                dp[j] = tp[j];
        }
    }
    LL zz = 2ll * F[m] * F[m] % mod;
    for(int i = 1; i <= 52; ++i)
        zz = (zz * Finv[cnt[i]]) % mod;
    int q, x, y;
    scanf("%d", &q);
    while(q--){
        scanf("%d%d", &x, &y);
        printf("%I64d\n", zz * ans[id(s[x])][id(s[y])] % mod);
    }
    return ;
}
int main(){
    init();
    while(~scanf("%s", s+1)){
        Ac();
    }
    return 0;
}

 

posted on 2019-02-18 23:27  zsben  阅读(137)  评论(0)    收藏  举报

导航