zoukankan      html  css  js  c++  java
  • 【HDU4947】GCD Array(莫比乌斯反演+树状数组)

    点此看题面

    大致题意: 一个长度为(n)的数组,实现两种操作:将满足(gcd(i,k)=d)(a_i)加上(v),询问(sum_{i=1}^xa_i)

    对于修改操作的推式子

    莫比乌斯反演真是个神奇而又有趣的东西......

    考虑修改操作是将满足(gcd(i,k)=d)(a_i)加上(v),则若(d ot| k),显然是不存在满足条件的(i)的,可以直接忽略这一修改操作(忘记判断结果调到心态爆炸......)

    否则,也就相当于:

    [a_i+=vcdot[gcd(i,k)=d] ]

    ([gcd(icdot d,k)=d])转化,即三个数同时除以(d),得到:

    [a_i+=vcdot[gcd(frac id,frac kd)=1] ]

    根据(sum_{p|x}mu(p)=[x=1])这一性质,我们就可以将上述式子再次变形,得到:

    [a_i+=sum_{p|frac id,p|frac kd}vcdotmu(p) ]

    因为原式中(p|frac id)这一限制等同于((pcdot d)|i),所以就等同于:

    [a_i+=sum_{(pcdot d)|i,p|frac kd}vcdot mu(p) ]

    如果我们枚举满足(p|frac kd)(p),并增开一个辅助数组(f),每次修改操作就相当于修改(f)

    [f_{pcdot d}+=vcdotmu(p) ]

    那么对于(a_i),其实就可以得到:

    [a_i=sum_{j|i}f_j ]

    对于询问操作的推式子

    题目询问我们(sum_{i=1}^xa_i)

    由之前推出的式子我们知道:

    [a_i=sum_{j|i}f_j ]

    所以,答案就是:

    [sum_{i=1}^xsum_{j|i}f_j ]

    调整枚举顺序,先枚举(j),得到:

    [sum_{j=1}^xlfloorfrac xj floor f_j ]

    所以,我们可以先除法分块,并利用树状数组实现对(f)的区间求和,即可得出答案了。

    代码

    #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 200000
    #define LL long long
    #define pb push_back
    using namespace std;
    int n;vector<int> v[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 put_case(CI x) {pc(67),pc(97),pc(115),pc(101),pc(32),pc(35),write(x),pc(58),pc(10);}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class LinearSieve//线性筛预处理莫比乌斯函数
    {
        private:
            int Pt,P[N+5],mu[N+5];
        public:
            I int operator [] (CI x) Con {return mu[x];}
            I LinearSieve()
            {
                mu[1]=1;for(RI i=2,j;i<=N;++i)
                    for(!P[i]&&(mu[P[++Pt]=i]=-1),j=1;j<=Pt&&1LL*i*P[j]<=N;++j)
                        if(P[i*P[j]]=1,i%P[j]) mu[i*P[j]]=-mu[i];else break;
            }
    }Mu;
    class TreeArray//树状数组实现单点修改、区间求和
    {
    	private:
    		LL a[N+5];
    	public:
    		I void Clear() {memset(a,0,sizeof(a));}
    		I void Add(RI x,CI y) {W(x<=n) a[x]+=y,x+=x&-x;}
    		I LL Qry(RI x,LL t=0) {W(x) t+=a[x],x-=x&-x;return t;}
    }T;
    int main()
    {
    	RI Tt=0,Qt,op,x,y,z,l,r;LL t;vector<int>::iterator it;
    	for(RI i=1,j;i<=N;++i) if(Mu[i]) for(j=i;j<=N;j+=i) v[j].pb(i);//预处理约数,注意μ=0可忽略
    	W(F.read(n),F.read(Qt),n&&Qt)
    	{
    		F.put_case(++Tt),T.Clear();W(Qt--) switch(F.read(op),F.read(x),op)
    		{
    			case 1:if(F.read(y),F.read(z),x%y) continue;x/=y;//注意判断不整除情况直接跳过
    				for(it=v[x].begin();it!=v[x].end()&&*it*y<=n;++it) T.Add(*it*y,Mu[*it]*z);break;//枚举约数在树状数组上修改
    			case 2:for(t=0,l=1;l<=x;l=r+1) r=x/(x/l),t+=(T.Qry(r)-T.Qry(l-1))*(x/l);F.writeln(t);break;//除法分块+树状数组求答案
    		}
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    mysql之优化器、执行计划、简单优化
    一条查询sql的执行流程和底层原理
    mysql建立索引,实际工作中建立索引的示例
    explain命令---查看mysql执行计划
    mysql 一些知识点
    开发中一些快捷键的使用
    simple-rpc
    maven
    数组合并排序
    SpringMVC配制全局的日期格式
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/HDU4947.html
Copyright © 2011-2022 走看看