HDU4407Sum ( 容斥原理)

来源:互联网 发布:ff14l雷霆捏脸数据 编辑:程序博客网 时间:2024/05/12 00:39

题目链接:

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


题意:

一个长度为n的序列,开始的序列为1,2,3....n;

然后又两种操作。

operation1: 询问区间[a,b]中与p互质的数的和。

operation2:将序号为i的数修改为x;

如果没有修改操作,那么狠明显就是一个容斥原理

计数的问题。

由于加上了修改,但是次数不多,因此我们可以将

修改后的点记录下来,然后先容斥记下数,然后遍历

记录的数组判断修改后的数是否要加上,之前的数

是否要去掉。


代码如下:

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <map>#include <vector>using namespace std;typedef long long LL;map<int,int > mp;map<int,int >::iterator it;vector<int >vc;void fen(int x){    vc.clear();    for(int i=2;i*i<=x;i++){        if(x%i==0){            vc.push_back(i);            while(x%i==0) x/=i;        }    }    if(x>1) vc.push_back(x);}LL solve(int x,int p){    LL ans =(LL)x*(x+1)/2;    fen(p);    //cout<<"vc.size() "<<vc.size()<<endl;    for(int i=1;i<(1<<vc.size());i++){        int cnt = 0;        LL tmp = 1;        for(int j=0;j<vc.size();j++){            if((1<<j)&i) tmp*=vc[j],cnt++;        }        LL k = x/tmp;        k = (k+1)*k/2*tmp;        if(cnt%2) ans -= k;        else ans += k;    }    return ans;}int gcd(int a,int b){    return b ? gcd(b,a%b) : a;}int main(){    int t,n,m,ord,x,y,p;    scanf("%d",&t);    while(t--){        mp.clear();        scanf("%d%d",&n,&m);        for(int i=0;i<m;i++){            scanf("%d",&ord);            if(ord==2){                scanf("%d%d",&x,&y);                mp[x]=y;            }            else{                scanf("%d%d%d",&x,&y,&p);                LL ans = solve(y,p)-solve(x-1,p);                //printf("ans= %d\n",ans);                for(it=mp.begin();it!=mp.end();it++){                    if(it->first>=x&&it->first<=y){                        if(gcd(it->first,p)==1) ans -= it->first;                        if(gcd(it->second,p)==1) ans +=it->second;                    }                }                printf("%I64d\n",ans);            }        }    }    return 0;}



1 0