hdu7013 String Mod 题解(单位根反演)

hdu7013 String Mod 题解(单位根反演)

比赛的时候不会单位根反演,一直在想用矩乘算出某条对角线的值然后类似解方程来做,可能可以\(O(k^3\log(L))\)

首先这个问题就是给定\((p,q)\),算:

\[\sum_{i=0}^L\sum_{j=0}^L [i\equiv p\text{ mod } n][j\equiv q\text{ mod }n]{L\choose i+j}{i+j\choose i}(k-2)^{L-i-j} \]

然后把\([i\equiv p\text{ mod }n]\)​​变成\([n|i-p]\)​​。

然后就是类似\(\sum_{i=0}^L [n|i] f(i)\)​。

对于\(\sum_{i=0}^Lf(i)\times w_{n}^{ki}\)​​​比较好算的可以单位根反演来做。

单位根反演:

\[[x|y]=\frac{1}{x}\sum_{i=0}^{x-1} w_{x}^{iy} \]

这个比较好证明:

后面的其实就是等比数列=\(w_x^x-1/w_x^y-1\)

显然若\(x|y\)​,每一个\(w_x^{iy}=1\)

否则上式分母不为零,而分子为零,所以值为0 。

\[\sum_{i=0}^L [n|i] f(n)\\ =\frac{1}{x} \sum_{i=0}^L \sum_{j=0}^{x-1} w_{x}^{ij}f(i)\\ =\frac{1}{x} \sum_{j=0}^{x-1} \sum_{i=0}^L w_{x}^{ij}f(i) \]

对于hdu的那题:

\[\frac{1}{n^2}\sum_{i=0}^L\sum_{j=0}^L (\sum_{f1=0}^{n-1} w_n^{f1(i-p)})(\sum_{f2=0}^{n-1} w_n^{f2(i-p)}){L\choose i+j}{i+j\choose i}(k-2)^{L-i-j}\\ =\frac{1}{n^2}\sum_{i=0}^L\sum_{j=0}^L (\sum_{f1=0}^{n-1} \frac{(w_n^{f1})^i}{{(w_n^{f1})}^p})(\sum_{f2=0}^{n-1} \frac{{(w_n^{f2})}^j}{{(w_n^{f1})}^p}){L\choose i+j}{i+j\choose i}(k-2)^{L-i-j}\\ =\frac{1}{n^2}\sum_{f1=0}^{n-1} \frac{1}{{(w_n^{f1})}^p}\sum_{f2=0}^{n-1} \frac{1}{{(w_n^{f1})}^p}\sum_{i=0}^L\sum_{j=0}^L (w_n^{f1})^i{(w_n^{f2})}^j{L\choose i+j}{i+j\choose i}(k-2)^{L-i-j}\\ \]

后面那两个式子的组合意义非常明显:

\[=\frac{1}{n^2}\sum_{f1=0}^{n-1} \frac{1}{{(w_n^{f1})}^p}\sum_{f2=0}^{n-1} \frac{1}{{(w_n^{f1})}^p}(w_n^{f1}+w_n^{f2}+k-2)^{L} \]

然后预处理就可以做到\(O(N^3+N^2\log L)\)

顺便说一下这题需要取模,所以不能用单位根,必须用原根,\(1e9+9\)的原根是13。

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int G=13;
const int MOD=1e9+9;
int quick(int A,int B){
	if(B==0) return 1;
	int tmp=quick(A,B>>1);
	tmp=1ll*tmp*tmp%MOD;
	if(B&1) tmp=1ll*tmp*A%MOD;
	return tmp;
}
int inv(int A){
	return quick(A,MOD-2);
}
const int MAXN=500;
int w[MAXN],iw[MAXN][MAXN];
int g[MAXN][MAXN];
void add(int & A,int B){
	A+=B;
	if(A>=MOD) A-=MOD;
}
int ans[MAXN][MAXN];
void solve(){
	int k;
	LL l;
	int n;
	scanf("%d%lld%d",&k,&l,&n);
	w[0]=1;
	w[1]=quick(G,(MOD-1)/n);
	rb(i,2,n-1) w[i]=1ll*w[i-1]*w[1]%MOD;
	rep(f1,n) rep(f2,n){
		g[f1][f2]=quick((1ll*w[f1]+w[f2]+k-2)%MOD,l%(MOD-1));
	}
	rep(i,n) rep(j,n) iw[i][j]=quick(inv(w[i]),j);
	int ivv=1ll*inv(n)*inv(n)%MOD;
	rep(i,n) rep(j,n) ans[i][j]=0;
	rep(p,n) rep(f2,n){
		int tmp=0;
		rep(f1,n){
			add(tmp,1ll*g[f1][f2]*iw[f1][p]%MOD);
		}
		rep(q,n){
			add(ans[p][q],1ll*tmp*iw[f2][q]%MOD);
		}
	}
	rep(i,n){
		rep(j,n){
			printf("%d",1ll*ans[i][j]*ivv%MOD);
			if(j!=n-1) printf(" ");
		}
		puts("");
	}
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--) solve();
	return 0;
}
posted @ 2021-08-03 22:09  WWW~~~  阅读(74)  评论(0编辑  收藏  举报