【题解】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;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!