ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P5224 - Candies(循环卷积)

2021-10-07 12:00:23  阅读:199  来源: 互联网

标签:洛谷 pw Candies res int 卷积 trs P5224 MOD


洛谷题面传送门

一道题解长度大概不到 1k 的题,可还是决定写篇题解,因为自己没有做出来(

\(1004535809\) 好评(

首先这个 \(\equiv m\pmod{k}\) 有点把我们往单位根反演的方向思考的意思,不过注意到 \(k\) 不一定是 \(1004535808\) 的约数,因此在多数情况下 \(k\) 次单位根是不存在的,因此我们只能放弃这个想法。

然后我便想着如何裂组合数,发现裂了之后还要再裂,如此不停递归下去,进而获得了复杂度优秀的 \(\mathcal O(nk)\) 的做法。看了题解才发现自己是多么 sb……

注意到这个组合数很容易让我们与二项式产生联想,具体来说 \(\dbinom{n}{i}=[x^i](1+x)^n\),而比较巧的一点是我们求和的组合数中所有组合数的上部都是相同的,也就是说答案就是 \((1+x)^n\) 中所有次数 \(\bmod k=m\) 的项的系数之和。看到次数 \(\bmod k\) 又能让我们发生怎样的联想呢?……循环卷积!我们考虑求 \((1+x)^n\) 时,对次数做 \(\bmod k\) 意义下的循环卷积,这样最终答案就是求得的长度为 \(k\) 的多项式中,\(x^m\) 前的系数。注意到 NTT 是可以解决循环卷积问题的,因此 NTT+循环卷积即可。

又帮我复习了一个 9 个月前学的东西(bushi,因为这东西大概 3 个月后还要再次学到)

const int MAXP=32768;
const int pr=3;
const int ipr=(MOD+1)/3;
void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int qpow(int x,int e){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
	return ret;
}
ll n;int m,K,rev[MAXP+5];
void NTT(vector<int> &a,int len,int type){
	int lg=31-__builtin_clz(len);
	for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
	for(int i=0;i<len;i++) if(rev[i]<i) swap(a[i],a[rev[i]]);
	static int pw_W[MAXP+5];pw_W[0]=1;
	for(int i=2;i<=len;i<<=1){
		int W=qpow((type<0)?ipr:pr,(MOD-1)/i);
		for(int j=((i>>1)-2);j>=0;j-=2) pw_W[j+1]=1ll*(pw_W[j]=pw_W[j>>1])*W%MOD;
		for(int j=0;j<len;j+=i){
			for(int k=0;k<(i>>1);k++){
				int X=a[j+k],Y=1ll*a[(i>>1)+j+k]*pw_W[k]%MOD;
				a[j+k]=(X+Y>=MOD)?(X+Y-MOD):(X+Y);
				a[(i>>1)+j+k]=(X-Y<0)?(X-Y+MOD):(X-Y);
			}
		}
	}
	if(!~type){
		int ivn=qpow(len,MOD-2);
		for(int i=0;i<len;i++) a[i]=1ll*a[i]*ivn%MOD;
	}
}
vector<int> conv(vector<int> a,vector<int> b){
	int LEN=1;while(LEN<a.size()+b.size()) LEN<<=1;
//	printf("A: ");for(int i=0;i<a.size();i++) printf("%d%c",a[i]," \n"[i+1==a.size()]);
//	printf("B: ");for(int i=0;i<b.size();i++) printf("%d%c",b[i]," \n"[i+1==b.size()]);
	a.resize(LEN,0);b.resize(LEN,0);NTT(a,LEN,1);NTT(b,LEN,1);
	for(int i=0;i<LEN;i++) a[i]=1ll*a[i]*b[i]%MOD;NTT(a,LEN,-1);
//	printf("mul: ");for(int i=0;i<a.size();i++) printf("%d%c",a[i]," \n"[i+1==a.size()]);
	while(a.size()>K){
		int pos=(int)(a.size())-1;
		add(a[pos%K],a[pos]);a.ppb();
	} return a;
}
int main(){
	scanf("%lld%d%d",&n,&m,&K);
	vector<int> res(1,1),trs(2,1);
	for(;n;n>>=1,trs=conv(trs,trs)) if(n&1) res=conv(res,trs);
	if(m>=res.size()) printf("0\n");
	else printf("%d\n",res[m]);
	return 0;
}

标签:洛谷,pw,Candies,res,int,卷积,trs,P5224,MOD
来源: https://www.cnblogs.com/ET2006/p/luogu-P5224.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有