zoukankan      html  css  js  c++  java
  • 【洛谷5071】[Ynoi2015] 此时此刻的光辉(莫队)

    点此看题面

    大致题意: 给出一个序列,每次询问一个区间中所有数乘积的约数个数。

    前言

    第一次看到这题的时候看到题解区清一色的(Pollard-Rho),果断弃疗。

    今天重新点开,再重新看了一遍题面,才发现这题似乎根本不用什么高级算法,只是普通的莫队+普通的乱搞而已。

    只不过我写得比较菜,一开始还(T)掉了一个点。后来在闪指导的指导下,把预处理求逆元时的快速幂求法改成了线性求逆元,结果就(2.31s)卡过了。。。

    (STO hl666 ORZ)

    前置知识

    对于一个数(n),设其质因数分解得到(p_1^{k_1} imes p_2^{k_2} imes... imes p_m^{k_m})(p_1,p_2,...,p_m)为互不相同的质数),则其约数个数就是(prod_{i=1}^m(k_i+1))

    这个式子的意思实际上就是枚举每一种质因子选几个。

    莫队

    由“前置知识”我们得到启发,要求约数个数,实际上只需要维护每个质因子的个数即可。

    怎么维护呢?毕竟这可是Ynoi啊,自然是用莫队喽!

    由于每个数最多只有(10)种质因子(因为最小的(10)个质数乘积已经超过(10^9)了),因此我们只要记录下这些质因子,就能方便快捷地维护了。

    质因数分解

    考虑如何求出一个数的质因子。当然是Pollard-Rho呀。

    我们可以先线性筛,筛出(sqrt{10^9})范围内的全部质数。

    对于每个需要分解的数,我们从小到大枚举质数,记下它的质因子并将该质因子除去(注意,这里是一个优化)。

    如果某一刻枚举到的质因子的平方大于该数了,就停止枚举。

    然后考虑剩下的这个数,如果它不为(1),则一定是一个质数(显然)。

    于是我们就实现了质因数分解。

    具体实现可以详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define X 19260817
    using namespace std;
    int n,m,a[N+5],k[N+5],p[N+5][15],t[N+5][15],sz,bl[N+5],Inv[30*N+5],v[103406],ans[N+5];
    map<int,int> pos;
    struct Qry
    {
    	int p,l,r;I Qry(CI i=0,CI a=0,CI b=0):p(i),l(a),r(b){}
    	I bool operator < (Con Qry& o) Con {return bl[l]^bl[o.l]?bl[l]<bl[o.l]:(bl[l]&1?r<o.r:r>o.r);}//莫队排序
    }q[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    struct LinearSieve
    {
    	#define LIM 31622
    	int Pt,P[LIM+5];
    	I LinearSieve()//线性筛筛质数
    	{
    		for(RI i=2,j,t;i<=LIM;++i) for(!P[i]&&(P[++Pt]=i,pos[i]=Pt),
    			j=1;j<=Pt&&(t=i*P[j])<=LIM;++j) if(P[t]=1,!(i%P[j])) break;
    	}
    }S;
    I void Init(CI id,RI v)
    {
    	static int cnt=S.Pt;
    	RI i;for(i=1;i<=S.Pt&&1LL*S.P[i]*S.P[i]<=v;++i) if(!(v%S.P[i]))//枚举
    		{p[id][++k[id]]=i;W(v/=S.P[i],++t[id][k[id]],!(v%S.P[i]));}//统计,并注意除去
    	if(v==1) return;if(!pos[v]) pos[v]=++cnt;p[id][++k[id]]=pos[v],t[id][k[id]]=1;//如果是1就不管,如果是一个新质数就记下来
    }
    int main()
    {
    	RI i,x;for(F.read(n),F.read(m),sz=sqrt(n),i=1;i<=n;++i) F.read(x),Init(i,x),bl[i]=(i-1)/sz+1;//读入,初始化
    	for(i=1;i<=m;++i) F.read(q[i].l),F.read(q[i].r),q[i].p=i;sort(q+1,q+m+1);//读入询问,排序
    	for(Inv[0]=Inv[1]=1,i=2;i<=30*N;++i) Inv[i]=X-1LL*X/i*Inv[X%i]%X;//线性求逆元
    	#define U(x,op) for(j=1;j<=k[x];++j)
    		res=1LL*res*Inv[v[p[x][j]]+1]%X,res=1LL*res*((v[p[x][j]]+=op*t[x][j])+1)%X;//莫队修改
    	RI j,L=1,R=0,res=1;for(i=1;i<=m;++i)//枚举询问,莫队
    	{
    		W(R<q[i].r) {++R;U(R,1);}W(L>q[i].l) {--L;U(L,1);}
    		W(R>q[i].r) {U(R,-1);--R;}W(L<q[i].l) {U(L,-1);++L;}ans[q[i].p]=res;
    	}
    	for(i=1;i<=m;++i) F.writeln(ans[i]);return F.clear(),0;//输出答案
    }
    
  • 相关阅读:
    金牙与肉屑
    科学研究的动机以及雄心
    适度的自我吹嘘
    ubuntu12启用root账户
    有很多文件夹是受系统保护的
    vs2012换肤功能,vs2012主题及自定义主题
    Ubuntu navicat for mysql 安装和使用
    Asp.Net MVC4 Bundle捆绑压缩技术
    64位Windows Jmail组件报错解决方案
    C#检测上传文件的真实类型
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5071.html
Copyright © 2011-2022 走看看