HDU 4407

http://acm.hdu.edu.cn/showproblem.php?pid=4407

把修改和询问分成两部分解决

询问求区间内与p不互素的和,和求个数一样,用容斥原理解决,只不过做容斥的时候把每一段的个数改成每一段的和,这个求和的方式我一下写搓了,导致这道题坑了很久

修改用map记录,每次扫一遍即可,原数和c互素就减掉,修改完的数和c互素就加上去,logn*m^2的复杂度

#include <iostream>

#include <cstdio>

#include <cstring>

#include <vector>

#include <map>

#include <cmath>



using namespace std;



typedef __int64 ll;



ll gcd(ll a,ll b){

    return b==0?a:gcd(b,a%b);

}



ll sum(ll l,ll r,ll k){

    ll num=r/k-(l-1)/k;

    ll front;

    if(l%k==0)front=l;

    else front=(k-l%k)+l;

    ll rear=r-r%k;

    return (front+rear)*num/2;

}



ll gao(ll l,ll r,ll n){

    vector <ll> v;

    for(ll i=2;i*i<=n;i++){

        if(n%i==0){

            v.push_back(i);

            while(n%i==0)n/=i;

        }

    }

    if(n>1)v.push_back(n);

    int m=v.size();

    ll res=0; 

    for(int i=1;i<(1<<m);i++){

        int cnt=0;

        ll val=1;

        for(int j=0;j<m;j++){

            if(i&(1<<j)){

                cnt++;

                val*=v[j];

            }

        }

        if(cnt&1)res+=sum(l,r,val);

        else res-=sum(l,r,val);

    }

    return (l+r)*(r-l+1)/2-res;

}



map <ll,ll> mp;

map <ll,ll>::iterator it;



ll gan(ll x,ll y,ll p){

    ll res=gao(x,y,p);

    for(it=mp.begin();it!=mp.end();it++){

        if(it->first>y || it->first<x)continue;

        if(gcd(it->first,p)==1)res-=it->first;

        if(gcd(it->second,p)==1)res+=it->second;

    }

    return res;

}



int main(){

    int T;

    scanf("%d",&T);

    while(T--){

        int n,m;

        scanf("%d%d",&n,&m);

        mp.clear();

        while(m--){

            int op;

            scanf("%d",&op);

            ll x,y,p;

            if(op==1){

                scanf("%I64d%I64d%I64d",&x,&y,&p);

                if(x>y)swap(x,y);

                printf("%I64d\n",gan(x,y,p));

            }

            else{

                scanf("%I64d%I64d",&x,&p);

                mp[x]=p;

            }

        }

    }

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)