hdu 7013 String Mod 题解

传送门


【大意】

\(A_{i, j}\) 表示长度为 \(L\) 的字符串,只用前 \(k(2\leq k\leq 26)\) 个小写字母,且 \(a\) 字母出现次数模 \(n\)\(i\)\(b\) 字母出现次数模 \(n\)\(j\) 的方案数

输出矩阵 \(A_{0\cdots (n-1), 0\cdots (n-1)}\)


【分析】

单位根反演题,现场过了一堆人我十分吃惊

一直认为是冷门算法

\(\displaystyle A_{i, j}=\sum_{p+q+r=L}\dbinom{L}{p, q, r}[p\bmod n=i]\cdot [q\bmod n=j]\cdot (k-2)^r\)

考虑单位根反演的公式:

\(\displaystyle [k\bmod n=0]={1\over n}\sum_{i=0}^{n-1}\omega_n^{ki}\)

代入得到:

\(\displaystyle A_{i, j}=\sum_{p+q+r=L}\dbinom{L}{p, q, r}{1\over n}\sum_{a=0}^{n-1}\omega_n^{(p-i)a}{1\over n}\sum_{b=0}^{n-1}\omega_n^{(q-j)b}\cdot (k-2)^r\)

调换求和顺序得到

\(\displaystyle A_{i, j}={1\over n^2}\sum_{a=0}^{n-1}\omega_n^{ai}\sum_{b=0}^{n-1}\omega_n^{bj}\sum_{p+q+r=L}\dbinom{L}{p, q, r}(\omega_n^a)^p\cdot (\omega_n^b)^q\cdot (k-2)^r\)

后面是个多项式定理的形式,合并得到:

\(\displaystyle A_{i, j}={1\over n^2}\sum_{a=0}^{n-1}\omega_n^{ai}\sum_{b=0}^{n-1}\omega_n^{bj}(\omega_n^a+\omega_n^b+k-2)^L\)

考虑到 \(n\mid (p-1)\)

故取 \(p\) 的原根 \(g\),即可令 \(\displaystyle \omega_n\equiv g^{p-1\over n}\pmod p\)


如果只求解单个,则复杂度没问题,但求和多个时,复杂度是不够的

考虑预处理 \(\displaystyle W_{a, b}=(\omega_n^a+\omega_n^b+k-2)^L\)

计算所有 \(W_{a, b}\) 的复杂度为 \(O(n^2\log p)\)

之后,我们预处理 \(\displaystyle S_a=\sum_{b=0}^{n-1}\omega_n^{bj}(\omega_n^a+\omega_n^b+k-2)^L=\sum_{b=0}^{n-1}\omega_n^{bj}\cdot W_{a, b}\)

计算 \(S_{0\cdots (n-1)}\) 的复杂度为 \(O(n^2)\)

最后,我们求解所有 \(A_{i, j}\) 时,由 \(\displaystyle A_{i, j}={1\over n^2}\sum_{a=0}^{n-1}\omega_n^{ai}\sum_{b=0}^{n-1}\omega_n^{bj}(\omega_n^a+\omega_n^b+k-2)^L={1\over n^2}\sum_{a=0}^{n-1}\omega_n^{ai}\cdot S_a\)

求解对所有的复杂度优化为 \(O(n^3)\)

故总复杂度为 \(O(n^3)\)


【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef double db;
#define fi first
#define se second
const int MOD=1e9+9, g=13;
ll k, l, n, omega[512], powit[512][512], t[512][512];
inline ll fpow(ll a,ll x) { ll ans=1; for(;x;x>>=1,a=a*a%MOD) if(x&1) ans=ans*a%MOD; return ans; }
inline int w(int val) { return (val%=n)>=0?omega[val]:omega[n+val]; }
inline int add(int a, int b) { return (a+=b)>=MOD?a-MOD:a; }

inline void pre(){
    cin>>k>>l>>n;
    omega[0]=1;
    omega[1]=fpow(g, (MOD-1)/n);
    for(int i=2;i<n;++i) omega[i]=omega[i-1]*omega[1]%MOD;

    for(int p=0;p<n;++p)
        for(int q=0;q<n;++q)
            powit[p][q]=fpow(k-2+w(-p)+w(-q), l);
    for(int a=0;a<n;++a)
        for(int j=0;j<n;++j){
            int res=0;
            for(int b=0;b<n;++b)
                res=add(res, w(b*j)*powit[a][b]%MOD);
            t[a][j]=res;
        }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    pre();
    ll C=fpow(n, MOD+MOD-4);
    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            int res=0;
            for(int a=0;a<n;++a)
                res=add(res, w(a*i)*t[a][j]%MOD);
            cout<<res*C%MOD<<" ";
        }
        cout<<"\n";
    }
    cout.flush();
    return 0;
}
posted @ 2021-08-09 23:06  JustinRochester  阅读(54)  评论(0编辑  收藏  举报