1. 程式人生 > 其它 >P3746 [六省聯考 2017] 組合數問題

P3746 [六省聯考 2017] 組合數問題

\[(\sum_{i=0}^\infty\binom{nk}{ik+r})\bmod p \]

其中 \(0\le r<k\le 50,1\le n\le10^9\)

\[\text{res}=\sum_{i\equiv r\pmod k}\binom{nk}{i}\\ =\sum_{i\equiv r\pmod k}[x^i](1+x)^{nk}\\ \]

好像可以單位根反演,

\[\text{res}=\sum_{i=0}^{k-1}\frac{(1+\omega_k^i)^{nk}}{\omega_k^{ir}} \]

但是 \(k\) 不固定,\(p\) 也不固定且非質數,不太好搞(涼涼)。

但是!單位根反演和迴圈卷積是存在一定的關係的,我們考慮單位根反演實際上求得就是迴圈卷積在某一位上的係數,我們考慮到這裡暴力做迴圈卷積是可行的,所以直接做即可。

#include<bits/stdc++.h>
using namespace std;
const int K=50;int MOD;
int ADD(int x,int y){return x+y>=MOD?x+y-MOD:x+y;}
int TIME(int x,int y){return (int)(1ll*x*y%MOD);}
long long n;int k,r;
struct Polynomial{int f[K];int &operator [] (int x){return f[x];}}f;
Polynomial operator * (Polynomial a,Polynomial b){
	Polynomial res={};
	for(int i=0;i<k;++i){
		for(int j=0;j<k;++j)
		res[(i+j)%k]=ADD(res[(i+j)%k],TIME(a[i],b[j]));
	}
	return res;
}
Polynomial operator ^ (Polynomial x,long long k){
	Polynomial res={1};
	for(;k;k>>=1,x=x*x) if(k&1) res=res*x;
	return res;
}
int main(){
	cin>>n>>MOD>>k>>r;
	f[0%k]++,f[1%k]++,f=(f^(n*k));
	return printf("%d\n",f[r]),0;
}