【题解】P3747 [六省联考2017]期末考试 (单位根反演)

【题解】P3747 [六省联考2017]组合数问题(单位根反演)

就是要我们求

\[\sum_{i=0}^k {nk\choose ik+r} \]

换一个形式

\[=\sum_{i=0}^{nk} {nk\choose i} [k|i-r] \]

单位根反演带入

\[={1\over k}\sum_{i=0}^{nk} {nk\choose i} \sum _{j=0}^{k-1} \omega_k^{(i-r)j} \]

凑一个二项式

\[={1\over k}\sum_{i=0}^{nk} \sum_{j=0}^{k-1} {nk\choose i} \omega_k^{ij}\cdot \omega_k^{-rj} \]

交换和式

\[={1\over k}\sum_{j=0}^{k-1} \omega_k^{-jr} \sum_{i=0}^{nk} {nk\choose i} \omega_k^{ij} \]

也就是

\[{1\over k}\sum_{j=0}^{k-1} \omega_k^{-jr} (1+\omega_k^j)^{nk} \]

(这个形式是一个FFT的形式),令\(f(x)=(1+x)^{nk}\),原式即

\[{1\over k} \sum_{j=0}^{k-1} \omega_k^{-jr} f(\omega_k^j) \]

考虑范德蒙德的逆矩阵,即

\[V_k^{-1}={1 \over k}\begin{pmatrix} {1}&{1}&{\cdots}&{1}\\ {1}&{\omega_k^{-1}}&{\cdots}&{\omega_k^{-(k-1)}}\\ {1}&{\omega_k^{-2}}&{\cdots}&{\omega_k^{-(k-1)2}}\\ {\vdots}&{\vdots}&{}&{\vdots}\\ {1}&{\omega_k^{-(k-1)}}&{\cdots}&{\omega_k^{-(k-1)(k-1)}}\\ \end{pmatrix} \]

\(f(\omega_k^j)\)是一个点值,而\({1\over k} \sum_{j=0}^{k-1} \omega_k^{-jr} f(\omega_k^j)\),就是:由点值构成的行向量\([f(\omega_k^0) \quad f(\omega_k^1)\dots f(\omega_k^{k-1})] \times V_{k}^{-1}\)的第\(r\)列的值!也就是\(f(x)\)这个多项式循环卷积(因为我们带入的都是\(k\)次单位根,于是\(f(x) \bmod x^k-1\)意义下的)意义下第\(r\)项的值。(根据dft和idft的定义)

然后这里\(k\)很小,直接暴力卷积即可

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;  typedef long long ll;
typedef vector<int> poly;
int n,mod,k,r;
int MOD(const int&x){return x>=mod?x-mod:x;}
int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
poly operator * (poly a,poly b){
	if(a.empty()||b.empty()) return poly(k,0);
	poly ret(k);
	for(int t=0,ed=a.size();t<ed;++t)
		for(int i=0,ed=b.size();i<ed;++i)
			ret[(t+i)%k]=MOD(ret[(t+i)%k]+MOD(a[t],b[i]));
	return ret;
}
poly ksm(ll x){
	poly ret(k,0),b(k,0);
	ret[0]=1; ++b[0]; ++b[1%k];
	while(x){
		if(x&1) ret=ret*b;
		b=b*b,x>>=1;
	}
	return ret;
}
int main(){
	cin>>n>>mod>>k>>r;
	cout<<ksm(1ll*n*k)[r]<<endl;
	return 0;
}



posted @ 2020-04-20 17:34  谁是鸽王  阅读(224)  评论(1编辑  收藏  举报