hdu4407(容斥原理+分解质因数)Sum

来源:互联网 发布:linux文件夹同步工具 编辑:程序博客网 时间:2024/05/22 15:26

题目大意是第一行输入T,第二行输入n,m,一个数组a[i]=i,下面m行每行一个操作,输入1,x,p,则表示把a[i]修改为p,输入2,x,y,p,则表示询问[x,y]区间内和p互质的数的个数

//比起原来的那个求一个数在一个区间里与之互质的个数,用map映射后,每次的求解最多多1000次判断互质计算//求和的时候两数相乘大于了int的范围,这个地方需要注意 #include<cstdio>#include<iostream>#include<map>#include<vector>#define ll long longusing namespace std;vector<int>  x;map<int,int> Map;int n,m;void getprime(int n){    //质因数分解,去掉相同的质因数    x.clear();    for(int i=2; i*i<=n; ++i)    {        if(n%i==0)        {            n/=i;            x.push_back(i);            while(n%i==0) n/=i;        }    }    if(n!=1) x.push_back(n);}bool gcd(int a,int b){    //判断a,b是否互质,互质返回真    while(b)    {        int t=a;        a=b;        b=t%b;    }    return a==1;}ll solve(int b,int p){    //求区间[1,b]中的数和p互质的数的个数    ll ans=(ll)b*(1+b)/2;    for(int i=1; i<(1<<x.size()); ++i)    {        int cnt=0;ll k=1;        for(int j=0; j<x.size(); ++j)            if(i&(1<<j)) ++cnt,k*=x[j];        k=(b/k)*(k+(b/k)*k)/2;//等差数列求和        if(cnt&1) ans-=k;        else ans+=k;    }    return ans;}ll sub(ll ans,int a,int b,int p){    for(map<int,int>::iterator it=Map.begin(); it!=Map.end(); ++it)    {        int f1=gcd(p,it->second),f2=gcd(it->first,p);        if(it->first<=b&&it->first>=a)        {            if(f1) ans+=it->second;            if(f2) ans-=it->first;        }    }    return ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        Map.clear();        scanf("%d%d",&n,&m);        int x,y,p;        while(m--)        {            scanf("%d",&x);            if(x==1)            {                scanf("%d%d%d",&x,&y,&p);                getprime(p);                printf("%lld\n",sub(solve(y,p)-solve(x-1,p),x,y,p));            }            else            {                scanf("%d%d",&x,&p);                Map[x]=p;            }        }    }    return 0;}