题意:给一个长度为n的序列,初始值为1~n;
对序列有以下两种操作;
1.查询[x,y]内与p互素的数的和;
2.修改第x数为c;
对于这道题,我们应该可以通过求【1,y】-【1,x-1】来得出答案;
我们先忽略操作2带来的影响,最后再通过暴力做法修改值即可(因为m范围只到1000,所以暴力不超时)
那么如何求区间答案呢;
我们有这样一个容斥定理:区间中与i不互质的个数=(区间中i的每个质因素的倍数个数)-(区间中i的每两个质因素的乘积的倍数个数)+
(区间中i的3个)-(4....)+(5....)-(6....)+(7.....)...... (偶数减,奇数加)
因为原序列为等差数列,我们可以得出前n项和公式,那么我们可以将问题转化为:区间内所有数的总和-区间内所有与p不互素的数的和
上面的定理求得是个数,但是我们可以转化为求和,比如素数是3,区间范围为1~10,那么就是3+6+9,而等比数列,假如首项为1,
则为n*(n+1)/2;而现在每一项都是某质数k的倍数,所以公式变为n*(n+1)/2*k,这样子就能根据定理一步步算出答案;
得出来之后,我们再走一遍暴力,将修改过的位置操作一下即可;
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn=400010; 5 int prime[maxn],cnt; ///保存素数,素数的个数 6 bool book[maxn]; 7 map<int ,int >mp; 8 vector<int> factor; 9 int gcd(int a,int b) 10 { 11 if(!b) return a; 12 else return gcd(b,a%b); 13 } 14 void Pri() ///线性筛素数 15 { 16 memset(book,0,sizeof(book)); 17 cnt=0; 18 book[0]=book[1]=1; 19 for(int i=2;i<maxn;i++) 20 { 21 if(!book[i]) prime[cnt++]=i; 22 for(int j=0;j<cnt&&prime[j]*i<maxn;j++){ 23 book[i*prime[j]]=1; 24 if(i%prime[j]==0) break; 25 } }} 26 27 LL F(LL k,LL n){ 28 return n*(n+1)/2*k; 29 } 30 LL solve(int n) ///解决[1,n] 内与p互素的和 31 { 32 LL sum=F(1LL,n); ///计算前n项和 33 LL item=1<<factor.size(); ///素因子个数 34 LL ans=0; 35 for(int i=1;i<item;i++) ///二进制容斥,都差不多的 36 { 37 int num=0,x=1; 38 for(int j=0;j<factor.size();j++){ 39 if(1&(i>>j)) { 40 num++;x*=factor[j]; 41 } 42 } 43 if(num&1) ans+=F(x,n/x); 44 else ans-=F(x,n/x); 45 } 46 return sum-ans; 47 48 } 49 int main() 50 { 51 int ncase; 52 Pri(); 53 scanf("%d",&ncase); 54 while(ncase--){ 55 mp.clear(); ///注意此处,每次测试案例都要清零 56 int n,m; 57 scanf("%d%d",&n,&m); 58 while(m--){ 59 int choice; 60 scanf("%d",&choice); 61 int x,y,c,p; 62 if(choice==1){ 63 scanf("%d%d%d",&x,&y,&p); 64 if(x>y) swap(x,y); 65 factor.clear(); ///初始化 66 int item=p; 67 for(int i=0;i<cnt;i++) ///求出p的素因子 68 { 69 if(prime[i]>item) break; 70 if(item%prime[i]==0){ 71 factor.push_back(prime[i]); 72 while(item%prime[i]==0) 73 item/=prime[i]; 74 } 75 } 76 ///这是另外一种求素因子的方法 77 // for(int i=2;i*i<=item;i++){ 78 // if(item%i==0){ 79 // factor.push_back(i); 80 // while(item%i==0) item/=i; 81 // } 82 // } 83 if(item>1) factor.push_back(item); 84 LL sum=solve(y)-solve(x-1); 85 map<int ,int >::iterator it;///迭代器,用来访问元素 86 for(it=mp.begin();it!=mp.end();it++) ///查找操作2对结果有没有影响 87 { 88 int a=it->first,b=it->second; 89 if(a>y||a<x) continue; 90 if(gcd(a,p)==1) sum-=a; ///本来互素的要减掉 91 if(gcd(b,p)==1) sum+=b;///修改后互素的要加上 92 } 93 printf("%lld\n",sum); 94 } 95 else{ 96 scanf("%d%d",&x,&c); 97 mp[x]=c; 98 } 99 } 100 } 101 return 0; 102 }