• 【HDU4676】Sum Of Gcd(莫队+欧拉函数)


    点此看题面

    大致题意: 多组询问,求(sum_{i=L}^Rsum_{j=i+1}^Rgcd(i,j))

    推式子

    这道题我们可以考虑,每个因数(d)被统计答案的次数,肯定与其出现次数有关。

    设它出现次数为(cnt_d),则可以猜测答案为:

    [sum_{d=1}^ndcdot C_{cnt_d}^2 ]

    这显然是错的,因为(d)虽作为公因数,却不一定是最大公约数。

    所以就可以考虑容斥

    对于一个统计过的数(x),按照我们先前的做法,对于任意(d|x)(d)一定都被统计过了。

    可以发现,这似乎恰好是一个欧拉函数

    于是式子就可以化成:

    [sumphi(d)*C_{cnt_d}^2 ]

    求解

    我们先用线性筛筛出欧拉函数,然后预处理出每个数的因数。

    接下来对于这种区间问题,自然可以用莫队来搞。

    每次转移时枚举因数更新答案即可。

    但还有个问题,枚举因数更新答案似乎会(TLE)

    但据(hl666)神仙证明,每个数的因数个数是(O(N^{frac13}))的!

    这样时间复杂度就是(O(N^{frac{11}6})),而(Nle20000),可以过。

    代码

    #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 20000
    #define LL long long
    using namespace std;
    int n,a[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^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		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--]);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void writes(Con string& x) {for(RI i=0,l=x.length();i^l;++i) pc(x[i]);}
    		I void clear() {fwrite(FO,1,C,stdout),C=0;}
    }F;
    class CaptainMotao//莫队
    {
    	private:
    		static const int Q=20000;int Bsz,cnt[N+5];LL res,ans[Q+5];
    		struct Query//存储询问
    		{
    			int l,r,bl,pos;I Query(CI x=0,CI y=0,CI b=0,CI p=0):l(x),r(y),bl(b),pos(p){}
    			I bool operator < (Con Query& t) const {return bl^t.bl?bl<t.bl:(bl&1?r<t.r:r>t.r);}//排序
    		}q[Q+5];
    		class LineSiever//初始化
    		{
    			private:
    				static const int SZ=N;int Pcnt,P[SZ+5];
    			public:
    				int phi[SZ+5];vector<int> fac[SZ+5];
    				I LineSiever()
    				{
    					RI i,j;for(phi[1]=1,i=2;i<=SZ;++i) for(!P[i]&&(phi[P[++Pcnt]=i]=i-1),j=1;1LL*i*P[j]<=SZ;++j)
    						if(P[i*P[j]]=1,i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1);else {phi[i*P[j]]=phi[i]*P[j];break;}
    					for(i=1;i<=SZ;++i) for(j=i;j<=SZ;j+=i) fac[j].push_back(i);
    				}
    		}S;
    		I void Add(CI x) {for(RI i=0,s=S.fac[x].size();i^s;++i) res+=1LL*S.phi[S.fac[x][i]]*cnt[S.fac[x][i]]++;}//增大区间
    		I void Del(CI x) {for(RI i=0,s=S.fac[x].size();i^s;++i) res-=1LL*S.phi[S.fac[x][i]]*--cnt[S.fac[x][i]];}//缩小区间
    	public:
    		I void Solve()//求解答案
    		{
    			RI Qtot,i,x,y,L=1,R=0;memset(cnt,0,sizeof(cnt)),Bsz=sqrt(n),F.read(Qtot);
    			for(i=1;i<=Qtot;++i) F.read(x,y),q[i]=Query(x,y,(x-1)/Bsz+1,i);//读入数据
    			for(res=0,sort(q+1,q+Qtot+1),i=1;i<=Qtot;++i)//排序并处理
    			{
    				W(R<q[i].r) Add(a[++R]);W(L>q[i].l) Add(a[--L]);W(R>q[i].r) Del(a[R--]);W(L<q[i].l) Del(a[L++]);//更新区间
    				ans[q[i].pos]=res;//记录答案
    			}static int t=0;F.writes("Case #"),F.write(++t),F.writes(":
    ");
    			for(i=1;i<=Qtot;++i) F.writeln(ans[i]);//输出答案
    		}
    }C;
    int main()
    {
    	RI Ttot,i;F.read(Ttot);W(Ttot--)
    	{
    		for(F.read(n),i=1;i<=n;++i) F.read(a[i]);//读入
    		C.Solve();//莫队求解
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    显而易见的python
    GitHub 使用教程图文详解
    linux下搭建hexo环境
    linux 删除软链接
    Django2.1入门教程
    windows下安装PyQt4
    python3 Flask安装
    学习之源
    白话C++系列教程
    面试笔试试题精选
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/HDU4676.html
Copyright © 2020-2023  润新知