LGP5071题解

我给这道题提供了314次提交qwq

题目大意

给定一个长为 \(n\) 的序列,每次询问给定一个 \(L\)\(R\),求 \([L,R]\) 中所有数乘起来的质因数个数,答案对 \(19260817\) 取余。

首先,静态区间,区间询问,想到莫队。

所有我们需要将所有质因数拆出来,莫队的时候转移。

时间复杂度: \(O(n\sqrt n)\)

你以为这就完了?善良毒瘤的lxl卡了常数Ynoi常见操作,所有我们需要优化。

拆分质因数,可以用 \(\rm PR\) 来分解质因数,不过还是太慢。其实我们可以给定一个小范围,把这个范围的质数都找出来,剩下的再用 \(\rm PR\)

那么这个范围应该是多少呢?

我们要让 \(\rm PR\) 的次数尽量小,然而 \(a_i \leq 10^9\),取 \(10^4\) 就如同暴力,取 \(10^2\) 又要很多次 \(\rm PR\),所以取 \(10^3\)\(1001^3 > 10^9\),说明在这个范围中,去掉小的因数就只有最多 \(2\) 个因数qwq。

于是我们交上去:link

T了。说明还能继续卡。

其实可以用 \(1 \sim 1000\) 中的质数来筛,最开始我使用的是打表,后来换成了xxs。

然后是莫队的转移。\(10^9\) 的范围内,一个数最多拥有 \(10\) 个质因数,那么每次转移的常数就很大,所以考虑开桶记录 \(1 \sim 1000\) 中所有质数在序列上的前缀和,直接减。

然后我们取得了84分的好成绩。

那么,我们还需要什么?

首先,只调用一次的函数拆封装,会影响效率。

其次,在一个函数中,假如有一个 \(Tp\) 类型的变量不会发生变化,我们就把 Tp a 改成 const Tp&a

然后,把所有 ==!= 换成用 ^ 实现的。

最后,\(fread\) 快读和 \(fwrite\) 快输是一定需要的qwq。

我们还差些什么?

rp,评测姬。

于是:link

麻麻快看!我A了一道Ynoi!

贴一下代码:

#pragma GCC optimize("Ofast,unroll-loops,fast-math")
#include<unordered_map>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cctype>
#include<cmath>
#define DEBUG printf("Baylor AK IOI\n");
int pcnt,prime[300005];bool zhi[1000005];
inline int mo(const long long&a,const int&mod){
	return a<mod?a:a-int(a/mod)*mod;
}
inline void sieve(const int&n){
	int i,j,x;
	for(i=2;i<=n;++i){
		if(!zhi[i])prime[++pcnt]=i;
		for(j=1;j<=pcnt&&(x=i*prime[j])<=n;++j){
			zhi[x]=true;
			if(!(i%prime[j]))break;
		}
	}
}
namespace IO{
	const int SIZE=1<<21;
	class istream{
	private:
		char buf[SIZE],*p1=buf,*p2=buf;
	public:
		inline char getchar(){
			if(p1==p2)p2=(p1=buf)+fread(buf,1,SIZE,stdin);
			return p1==p2?-1:*p1++;
		}
		inline istream&operator>>(int&a){
			char s;
			a=0;
			while(!isdigit(s=getchar()));
			while(a=a*10+(s^48),isdigit(s=getchar()));
			return*this;
		}
	}cin;
	class ostream{
	private:
		int p1=-1;
		char buf[SIZE];
		const int p2=SIZE-1;
	public:
		inline void flush(){
			fwrite(buf,1,p1+1,stdout);
			p1=-1;
		}
		inline void putchar(const char&s){
			if(p1==p2)flush();
			buf[++p1]=s;
		}
		inline ostream&operator<<(int&n){
			static char s[33];
			int top=0;
			while(s[++top]=(n%10)^48,n/=10);
			while(putchar(s[top]),--top);
			return*this;
		}
	}cout;
}
namespace Pollard_Rho{
	inline int abs(const int&a){
		return a>0?a:-a;
	}
	inline int Rand(const int&mod){
		return mo(rand()*rand(),mod);
	}
	const int Pcnt=2;
	const int p[Pcnt]={61,103};
	inline int min(const int&a,const int&b){
		return a>b?b:a;
	}
	inline int gcd(register int a,register int b){
		while(b^=a^=b^=a%=b);
		return a;
	}
	inline int pow(register int a,register int b,const register int&mod){
		register int ans=1;
		for(;b;b>>=1,a=mo(1ll*a*a,mod))if(b&1)ans=mo(1ll*ans*a,mod);
		return ans;
	}
	bool IsPrimeIt(const register int&n){
		if(n%6^1&&n%6^5||n<2)return false;
		if(n<=1000000)return!zhi[n];
		register int m=n-1,k=__builtin_ctz(m);m>>=k;
		for(register int i,j=0;j^Pcnt;++j){
			register int x=pow(p[j],m,n),y=x;
			for(i=0;i^k;++i){
				x=mo(1ll*x*x,n);
				if(!(x^1)&&(y^1)&&(y^n-1))return false;
				y=x;
			}
			if(x^1)return false;
		}
		return true;
	}
	inline int PR(const register int&x){
		register int len=0,k=1;
		register int v0=Rand(x-1)+1,v=v0,y=Rand(x-1)+1,d,s=1;
		while(true){
			v=mo((mo(1ll*v*v,x)+y),x),s=mo(1ll*s*abs(v-v0),x);
			if(v==v0||!s)return x;
			if(++len==k){
				if((d=gcd(s,x))^1)return d;
				v0=v;k<<=1;
			}
		}
	}
	inline int dmp(const int&x){
		int d;
		while((d=PR(x))==x);
		return d;
	}
}
namespace Main{
	const int M=1e5+5,mod=19260817;
	int n,m,d[M],top[M],a[M][3],sum[M][169];
	std::unordered_map<int,int>Dct;
	int tp,pri[M<<1],inv[M<<1];
	int p,cur=1,ans[M],cnt[M<<1];
	struct Query{
		int L,R,p1,p2,id;
		inline bool operator<(const Query&a) const {
			return p1^a.p1?L<a.L:p1&1?R<a.R:R>a.R;
		}
	}q[M];
	inline int abs(const int&a){
		return (a>0?0:n<<1)+a;
	}
	inline void Add(const register int&id){
		for(register int i=1;i<=top[id];++i){
			cur=1ll*cur*inv[abs(cnt[a[id][i]])]%mod*abs(++cnt[a[id][i]])%mod;
		}
	}
	inline void Del(const register int&id){
		for(register int i=1;i<=top[id];++i){
			cur=1ll*cur*inv[abs(cnt[a[id][i]])]%mod*abs(--cnt[a[id][i]])%mod;
		}
	}
	inline void main(){
		register int i,j,L=1,R=0;
		IO::cin>>n>>m;
		p=n/sqrt(2.0*m/3);
		for(i=1;i<=n;++i){
			int&val=d[i],x;
			IO::cin>>val;
			memcpy(sum[i],sum[i-1],676);
			for(j=1;j<=168&&(x=prime[j])<=val;++j){
				if(!(val%x)){
					while(!(val%x)){
						++sum[i][j];
						val/=x;
					}
				}
			}
			if(!(val^1))continue;
			if(Pollard_Rho::IsPrimeIt(val)){
				a[i][++top[i]]=pri[++tp]=val;
				continue;
			}
			while(!((x=Pollard_Rho::PR(val))^val));
			if(x*x==val){
				a[i][++top[i]]=pri[++tp]=x;
				a[i][++top[i]]=x;
				continue;
			}
			a[i][++top[i]]=pri[++tp]=x;
			a[i][++top[i]]=pri[++tp]=val/x;
		}
		std::sort(pri+1,pri+tp+1);
		for(i=1;i<=tp;++i)cnt[Dct[pri[i]]=i]=1;
		for(i=1;i<=n;++i){
			for(j=1;j<=top[i];++j){
				a[i][j]=Dct[a[i][j]];
			}
		}
		inv[1]=1;
		for(i=2;i<=(n<<1);++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		for(i=1;i<=m;++i){
			IO::cin>>(q+i)->L>>(q+i)->R;
			(q+i)->p1=(q+i)->L/p;(q+i)->p2=(q+i)->R/p;
			(q+i)->id=i;
		}
		std::sort(q+1,q+m+1);
		for(i=1;i<=m;++i){
			int&QL=(q+i)->L,&QR=(q+i)->R;
			while(L<QL)Del(L++);
			while(R>QR)Del(R--);
			while(L>QL)Add(--L);
			while(R<QR)Add(++R);
			int&out=ans[(q+i)->id];out=cur;
			for(j=1;j<=168;++j)out=mo(1ll*out*(sum[QR][j]-sum[QL-1][j]+1),mod);
		}
		for(i=1;i<=m;++i)IO::cout<<ans[i],IO::cout.putchar(10);
	}
}
signed main(){
	srand(19260817);
	sieve(1000000);
	Main::main();
	IO::cout.flush();
}
posted @ 2022-01-10 15:23  Prean  阅读(6)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};