2018.12.07【LOJ6019】寻找LCM(组合数学)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/84888054

传送门


解析:

有点小骚的操作啊。。。

很是妙妙的一道题,最开始教练是抱着让我卡常的心态做的。然后根本优化不动。。。

一看AC了的代码。。。WOC真的很妙妙。

思路:

首先不要想 e x L u c a s e exLucase 了,复杂度不对的。。。

那么怎么弄?

题目要求的东西就是 C c i x i ( m o d   p ) \prod C_{c_i}^{x_i} (mod\text{ }p)

然后其实我们可以分别统计每个数的阶乘在实际操作中贡献的次数。

那么后缀和就是每个数实际上求出来的次数。

直接快速幂就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
	return num;
}

cs int N=1000006;
int n,p;
int cnt[N];

int minpri[N];
int prime[N],pcnt;
inline void linear_sieves(int len=N-6){
	for(int re i=2;i<=len;++i){
		if(!minpri[i])minpri[i]=i,prime[++pcnt]=i;
		for(int re j=1;i*prime[j]<=len&&j<=pcnt;++j){
			minpri[i*prime[j]]=prime[j];
			if(i%prime[j]==0)break;
		}
	}
}

inline int quickpow(int a,int b){
	re int ans=1;
	while(b){
		if(b&1)ans=(ll)ans*a%p;
		a=(ll)a*a%p;
		b>>=1;
	}
	return ans;
}

int x[N],c[N],ans=1;
signed main(){
	linear_sieves();
	n=getint(),p=getint();
	for(int re i=1;i<=n;++i)x[i]=getint();
	for(int re i=1;i<=n;++i)c[i]=getint();
	for(int re i=1;i<=n;++i)++cnt[c[i]],--cnt[x[i]],--cnt[c[i]-x[i]];
	for(int re i=N-6;i>=1;--i)cnt[i]+=cnt[i+1];
	for(int re i=N-6;i>1;--i)
	if(cnt[i]){
		if(minpri[i]==i)ans=(ll)ans*quickpow(i,cnt[i])%p;
		else cnt[minpri[i]]+=cnt[i],cnt[i/minpri[i]]+=cnt[i];
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/84888054