题目背景
JerryC有一大袋糖果,他正以1\ t/ms1 t/ms的速度食用着这一袋糖果…
题目描述
JerryC的糖果有NN箱(两两之间不同)。他一开始想挑MM箱出来,但是觉得吃起来不过瘾,所以又想要多拿一些出来。由于他比较喜欢数字KK,所以只要拿出来的糖的量x(x \ge M)x(x≥M)满足:x \equiv M\ (\bmod\ K)x≡M (mod K),JerryC就会得到满足感。
求有多少种方案使得JerryC得到满足感。请输出方案数\bmod\ 1004535809mod 1004535809的结果。
输入格式
一行三个非负整数NN,MM,KK。
输出格式
一行一个非负整数,表示方案数\bmod\ 1004535809mod 1004535809的结果。
输入输出样例
输入 #1复制
10 2 3
输出 #1复制
342
说明/提示
样例解释:
可以拿出来:2箱 5箱 8箱,组合数算一下就是了:
\binom{10}{2}+\binom{10}{5}+\binom{10}{8}=342( 210 )+( 510 )+( 810)=342数据范围:
测试点编号 N\leN≤ K\leK≤
11 11 11
2-32−3 10^610
6
1010
4-84−8 10^{12}10
12
100100
9-129−12 10^{15}10
15
10^310
3
12-2012−20 10^{18}10
18
10^410
4
0 \leq M < K
0≤M<K
其实这道题就是循环卷积,求的就是(1+x) nmod(x k−1)。
看完题后直接可以列出公式
(1+x) n=i=0∑n( in)x i
这时候把指数模上k后所得结果相同的列在一起就是答案了.
本算法的时间复杂度 O(k\log k\log n)O(klogklogn)
特殊情况下(k为2的幂次方或其他特殊情况时)为 O(k\log k)O(klogk)
代码
#include<bits/stdc++.h>
#define ll long long
#define N 400007
#define reg register
#define p 1004535809
using namespace std;
struct poly{
int a[N];
int t;
};
int rev[N];
int inv;
inline int power(int a,int t){
int res = 1;
while(t){
if(t&1) res = (ll)res*a%p;
a = (ll)a*a%p;
t >>= 1;
}
return res;
}
inline void NTT(poly &f,int type,int lim){
for(reg int i=1;i<=lim;++i){
if(i>=rev[i]) continue;
swap(f.a[i],f.a[rev[i]]);
}
reg int w,r,x,y,rt;
for(reg int mid=1;mid<lim;mid<<=1){
r = mid<<1;
rt = power(3,(p-1)/r);
if(type==-1) rt = power(rt,p-2);
for(reg int j=0;j<lim;j+=r){
w = 1;
for(reg int k=0;k<mid;++k){
x = f.a[j+k];
y = (ll)w*f.a[j+k+mid]%p;
f.a[j+k] = (x+y)%p;
f.a[j+k+mid] = (x-y+p)%p;
w = (ll)w*rt%p;
}
}
}
}
ll n;
int m,k,lim,l;
poly F;
poly power(poly f,ll n){
poly g,h;
g.t = f.t;
memset(g.a,0,sizeof(g.a));
g.a[0] = 1;
while(n){
if(n&1){
h = f;
NTT(h,1,lim),NTT(g,1,lim);
for(reg int i=0;i<=lim;++i)
g.a[i] = (ll)g.a[i]*h.a[i]%p;
NTT(g,-1,lim);
for(reg int i=0;i<=lim;++i)
g.a[i] = (ll)g.a[i]*inv%p;
for(reg int i=k;i<=lim;++i){
g.a[i%k] = (g.a[i%k]+g.a[i])%p;
g.a[i] = 0;
}
}
n >>= 1;
if(!n) break;
NTT(f,1,lim);
for(reg int i=0;i<=lim;++i)
f.a[i] = (ll)f.a[i]*f.a[i]%p;
NTT(f,-1,lim);
for(reg int i=0;i<=lim;++i)
f.a[i] = (ll)f.a[i]*inv%p;
for(reg int i=k;i<=lim;++i){
f.a[i%k] = (f.a[i%k]+f.a[i])%p;
f.a[i] = 0;
}
}
return g;
}
signed main(){
scanf("%lld%d%d",&n,&m,&k);
lim = 1,l = -1;
while(lim<=(k<<1)){
lim <<= 1;
++l;
}
inv = power(lim,p-2);
for(reg int i=1;i<=lim;++i)
rev[i] = (rev[i>>1]>>1)|((i&1)<<l);
F.t = lim;
F.a[0] = F.a[1] = 1;
F = power(F,n);
printf("%d",F.a[m]);
return 0;
}