CF#537 | Destroy the Colony


https://codeforces.com/contest/1111/problem/D

We first find the generating function of whole elements.

\begin{align}
(1+x^\bigcirc)(1+x^\bigcirc) \cdots (1+x^\bigcirc)
\end{align}

Dividing $(1+x^\bigcirc)^{-1}$, we obtain the answer.

#include <stdio.h>
#include <string.h>

#define MOD 1000000007

struct mint {
    int n;
    mint(int n_ = 0) : n(n_) {}
};

mint operator+(mint a, mint b) { a.n += b.n; if (a.n >= MOD) a.n -= MOD; return a; }
mint operator-(mint a, mint b) { a.n -= b.n; if (a.n < 0) a.n += MOD; return a; }
mint operator*(mint a, mint b) { return (long long)a.n * b.n % MOD; }
mint &operator+=(mint &a, mint b) { return a = a + b; }
mint &operator-=(mint &a, mint b) { return a = a - b; }
mint &operator*=(mint &a, mint b) { return a = a * b; }

mint F[100001] = {1, 1};
mint IF[100001] = {1, 1};
mint I[100001] = {0, 1};

mint dp[53][50001];
int N;
char S[100001];
int A[52];
int A_[52];

int min(int x, int y) {
    return x < y ? x : y;
}

int f(int c) {
    if ('a' <= c && c <= 'z') {
        return c - 'a';
    } else {
        return c - 'A' + 26;
    }
}

void susume(int i) {
    if (A[i] == 0) {
        for (int j = 0; j <= N / 2; j++) {
            dp[i + 1][j] = dp[i][j];
        }
    } else {
        for (int j = 0; j <= N / 2; j++) {
            if (j >= A[i]) {
                dp[i + 1][j] = dp[i][j] + dp[i][j - A[i]];
            } else {
                dp[i + 1][j] = dp[i][j];
            }
        }
    }
}

void modore(int i) {
    for (int j = 0; j <= N / 2; j++) {
        if (j >= A[i]) {
            dp[i][j] = dp[i + 1][j] - dp[i][j - A[i]];
        } else {
            dp[i][j] = dp[i + 1][j];
        }
    }
}

int main() {
    for (int i = 2; i <= 100000; i++) {
        I[i] = I[MOD % i] * (MOD - MOD / i);
        F[i] = i * F[i - 1];
        IF[i] = I[i] * IF[i - 1];
    }
    scanf("%s", S);
    N = strlen(S);
    for (int i = 0; i < N; i++) {
        A[f(S[i])]++;
    }
    dp[0][0] = 1;
    for (int i = 0; i < 52; i++) {
        susume(i);
    }
    for (int i = 0; i < 52; i++) {
        A_[i] = A[i];
    }
    static mint ans[52][52];
    for (int x = 0; x < 52; x++) {
        if (A_[x] == 0) continue;
        ans[x][x] = dp[52][N / 2];
        A[51] = A_[x];
        modore(51);
        for (int y = x + 1; y < 52; y++) {
            if (A_[y] == 0) continue;
            A[50] = A_[y];
            modore(50);
            int s = A_[x] + A_[y];
            if (s > N / 2) {
                ans[x][y] = ans[y][x] = 0;
            } else {
                ans[x][y] = ans[y][x] = dp[50][N / 2] + dp[50][N / 2 - s];
            }
        }
    }
    mint v = F[N / 2] * F[N / 2];
    for (int i = 0; i < 52; i++) {
        v *= IF[A_[i]];
    }
    int q;
    scanf("%d", &q);
    while (q--) {
        int x, y;
        scanf("%d %d", &x, &y);
        x--; y--;
        x = f(S[x]);
        y = f(S[y]);
        printf("%d\n", (v * ans[x][y]).n);
    }
    return 0;
}