hdu4407 Sum(容斥原理)

来源:互联网 发布:可以听pdf的软件 编辑:程序博客网 时间:2024/06/01 19:17

题意:已知序列1,2…n。存在两个操作
1,x,y,p:统计[x,y]位置区间内有多少个元素与p互素
2,x.c:将x位置上的数改成c
n<=400000,操作数m<=1000
解法:由于操作数较小,所以先处理未操作的结果,然后再考虑数字置换后结果的该变量。
未操作时的结果:统计[x,y]中有多少个元素与p互素
这是经典的容斥原理问题,见前文博客。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <vector>#include <algorithm>#include <queue>#define mem(a , b) memset(a , b , sizeof(a))#define pb(a) push_back(a)#define mp(a,b) make_pair(a,b)using namespace std;typedef long long ll;const int maxn = 400000+10;ll n,m,t;vector<ll> change;//改变序列ll dp[maxn];//i点修改过的值ll ans;vector<ll> factor;vector<ll> prime;bool not_prime[maxn];void make_prime(){    for(ll i=2;i<maxn-5;i++){        if(!not_prime[i]) prime.push_back(i);        for(ll j=0;j<prime.size()&&prime[j]*i<maxn-5;j++){            not_prime[i*prime[j]]=1;            if(!(i%prime[j])) break;        }    }}//分解因子复杂度:O(sqrt(n))void divided(ll x){    factor.clear();    for(ll i=0;i<prime.size();i++){        if(prime[i]*prime[i]>x) break;        if(x%prime[i]==0){            factor.push_back(prime[i]);            while(x%prime[i]==0) x/=prime[i];        }    }    if(x!=1) factor.push_back(x);}ll gcd(ll a,ll b){    return b==0?a:gcd(b,a%b);}ll sum(ll x,ll p){//[1,x]中与p互素数的和    ll len=factor.size();    ll ans=0;    for(ll i=1;i<(1<<len);i++){        ll tmp=0,tmpans=1;        for(ll j=0;(1<<j)<=i;j++){            if((1<<j)&i){                if(tmp) tmp=0; else tmp=1;                tmpans*=factor[j];            }        }        ll k=x/tmpans;        if(tmp) ans=ans+k*(k+1)*tmpans/2;//奇数次        else ans=ans-k*(k+1)*tmpans/2;//偶数次    }    return x*(x+1)/2-ans;}int main(){    //freopen("a.txt","r",stdin);    make_prime();    scanf("%lld",&t);    while(t--){        memset(dp,-1,sizeof(dp));        change.clear();        scanf("%lld%lld",&n,&m);        for(ll i=1;i<=m;i++){            ll flag,x,y,p,c;            scanf("%lld",&flag);            if(flag==2){                scanf("%lld%lld",&x,&c);                if(dp[x]==-1){                    change.push_back(x);                    dp[x]=c;                }                else dp[x]=c;            }            else{                scanf("%lld%lld%lld",&x,&y,&p);                ans=0;                divided(p);                ans=sum(y,p)-sum(x-1,p);                for(int j=0;j<change.size();j++){                    int a=change[j];                    if(a>=x&&a<=y){                        if(gcd(a,p)==1) ans=ans-a;                        if(gcd(dp[a],p)==1) ans=ans+dp[a];                    }                }                printf("%lld\n",ans);            }        }    }}
0 0