[单位根反演] HDU 7013 String Mod

题目大意

对于所有由前 \(k\) 个小写英文字母组成的长为 \(L\) 的字符串,设 \(A[i][j]\) 表示字符串中 a 的数量模 \(n\) 等于 \(i\),b 的数量模 \(n\) 等于 \(j\) 这样的字符串个数。输出矩阵 \(A\)\(2\leq k\leq 26,1\leq L\leq 10^{18},1\leq n\leq 500\)

题解

设字符串中含有 \(x\) 个 a 和 \(y\) 个 b,对 \(x,y\) 进行枚举,有

\[A[i][j]=\sum_{x=0}^L\sum_{y=0}^{L-x} [n|x-i][n|y-j]\binom{L}{x}\binom{L-x}{y}(k-2)^{L-x-y}\\ \]

考虑换掉艾弗森约定,可以使用单位根反演:

单位根反演

\[\forall k,[n|k]=\frac{1}{n}\sum_{i=0}^{n-1} \omega_n^{ik} \]

证明:

  1. \(n|k\) 时,\(\omega_n^{ik}=\omega_n^0=1\)\(\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ik}=1=[n|k]\)

  2. \(n\nmid k\) 时,

\[\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ik}=\frac{1}{n}\cdot\frac{\omega_n^{nk}-1}{\omega_n^k-1}=\frac{1}{n}\cdot\frac{1-1}{\omega_n^k-1}=0=[n|k] \]

所以有

\[A[i][j]=\sum_{x=0}^L\sum_{y=0}^{L-x} [n|x-i][n|y-j]\binom{L}{x}\binom{L-x}{y}(k-2)^{L-x-y}\\ =\sum_{x=0}^L\sum_{y=0}^{L-x} \left(\frac{1}{n}\sum_{p=0}^{n-1}\omega_n^{p(x-i)}\right)\left(\frac{1}{n}\sum_{q=0}^{n-1}\omega_n^{q(y-j)}\right)\binom{L}{x}\binom{L-x}{y}(k-2)^{L-x-y}\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\sum_{x=0}^L\sum_{y=0}^{L-x} \omega_n^{p(x-i)}\omega_n^{q(y-j)}\binom{L}{x}\binom{L-x}{y}(k-2)^{L-x-y}\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\sum_{x=0}^L\sum_{y=0}^{L-x} \omega_n^{px}\omega_n^{qy}\omega_n^{-pi}\omega_n^{-qj}\binom{L}{x}\binom{L-x}{y}(k-2)^L(k-2)^{-x}(k-2)^{-y}\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\omega_n^{-pi}\omega_n^{-qj}\sum_{x=0}^L\sum_{y=0}^{L-x} \omega_n^{px}\omega_n^{qy}\binom{L}{x}\binom{L-x}{y}(k-2)^{L-x-y}\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\omega_n^{-pi}\omega_n^{-qj}\sum_{x=0}^L\binom{L}{x}\omega_n^{px}\sum_{y=0}^{L-x} \binom{L-x}{y}(k-2)^{L-x-y}(\omega_n^q)^y\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\omega_n^{-pi}\omega_n^{-qj}\sum_{x=0}^L\binom{L}{x}(\omega_n^q+k-2)^{L-x}(\omega_n^p)^x\\ =\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}\omega_n^{-pi}\omega_n^{-qj}(\omega_n^p+\omega_n^q+k-2)^L \]

\(P(i,p)=\omega_{n}^{-pi},Q(p,q)=(\omega_n^p+\omega_n^q+k-2)^L,R(q,j)=\omega_n^{-qj}\)

\(A[i][j]=\frac{1}{n^2}\sum_{p=0}^{n-1}\sum_{q=0}^{n-1}P(i,p)Q(p,q)R(q,j)\)

可以作两次矩阵乘法得到答案。

Code

#include <bits/stdc++.h>
using namespace std;

#define RG register int
#define LL long long

const LL p = 1e9 + 9;

LL qpow(LL b, LL n) {
    LL x = 1, Power = b % p;
    while (n) {
        if (n & 1) x = x * Power % p;
        Power = Power * Power % p;
        n >>= 1;
    }
    return x;
}

struct Matrix {
    LL a[502][502];
    int n;
    Matrix operator*(const Matrix& r) {
        Matrix res;
        res.n = n;
        memset(res.a, 0, sizeof(res.a));
        for (int k = 0;k < n;++k)
            for (int i = 0;i < n;++i)
                for (int j = 0;j < n;++j)
                    res.a[i][j] = (res.a[i][j] + a[i][k] * r.a[k][j] % p) % p;
        return res;
    }
};
LL x[505], L;
int q[505];
Matrix ans, A, B, C;
int T, k, n;

void solve() {
    ans.n = A.n = B.n = C.n = n;
    LL g = qpow(13, (p - 1) / n);
    x[0] = 1;
    for (int i = 1;i < n;++i) x[i] = x[i - 1] * g % p;
    for (int i = 0;i < n;++i)
        for (int j = 0;j < n;++j) {
            A.a[i][j] = qpow(g, i * j);
            B.a[i][j] = qpow(x[i] + x[j] + k - 2, L);
        }
    C = A;
    for (int i = 0;i < n;++i)
        for (int j = 0;j < i;++j)
            swap(C.a[i][j], C.a[j][i]);
    ans = A * B;ans = ans * C;
    LL m = qpow(n * n, p - 2);
    for (int i = 1;i < n;++i) q[i] = n - i;
    for (int i = 0;i < n;++i) {
        for (int j = 0;j < n;++j) {
            printf("%lld", ans.a[q[i]][q[j]] * m % p);
            if (j < n - 1) printf(" ");
        }
        printf("\n");
    }
    return;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%lld%d", &k, &L, &n);
        solve();
    }
    return 0;
}
posted @ 2021-08-06 10:21  AE酱  阅读(48)  评论(0编辑  收藏  举报