标签:
题目链接:
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; }
标签:
原文地址:http://blog.csdn.net/bigbigship/article/details/44921821