容斥原理:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 1010; 6 const int Ni = 400010; 7 bool isprime[Ni]; 8 int id[Ni],tp,pr[30]; 9 int prime[40000],cnt; 10 int ax[N],ac[N]; 11 void Prime(){ 12 cnt=0; 13 memset(isprime,true,sizeof(isprime)); 14 for(int i=2;i<Ni;i++){ 15 if(isprime[i]){ 16 for(int j=i+i;j<Ni;j+=i) 17 isprime[j]=false; 18 prime[cnt++]=i; 19 } 20 } 21 } 22 int gcd(int a,int b){ 23 if(b==0) return a; 24 return gcd(b,a%b); 25 } 26 long long finds(int x,int n,int p){ 27 int t,i,j,num,d,m=1<<n; 28 long long ans=(long long)x*(x+1)/2; 29 for(i=1;i<m;i++) { 30 t=i;j=num=0;d=1; 31 while(t) { 32 if(t&1) {d*=pr[j];num++;} 33 j++;t>>=1; 34 } 35 n=x/d; 36 if(num&1) ans-=(long long )d*(1+n)*n/2; 37 else ans+=(long long) d*(1+n)*n/2; 38 } 39 for(i=0;i<tp;i++) { 40 if(ax[i]>x) continue; 41 if(gcd(ax[i],p)==1) ans-=ax[i]; 42 if(gcd(ac[i],p)==1) ans+=ac[i]; 43 } 44 return ans; 45 } 46 int pri(int a){ 47 if(isprime[a]) {pr[0]=a;return 1;} 48 int k=0,i; 49 for(i=0;i<cnt;i++){ 50 if(a%prime[i]==0) pr[k++]=prime[i]; 51 while(a%prime[i]==0) a/=prime[i]; 52 if(a!=1&&isprime[a]) {pr[k++]=a;return k;} 53 } 54 return k; 55 } 56 int main() 57 { 58 Prime(); 59 int n,m,x,y,op,p,cs; 60 scanf("%d",&cs); 61 while(cs--){ 62 scanf("%d%d",&n,&m); 63 tp=0; memset(id,-1,sizeof(id)); 64 for(int i=0;i<m;i++){ 65 scanf("%d",&op); 66 if(op==1){ 67 scanf("%d%d%d",&x,&y,&p); 68 int num=pri(p); 69 printf("%I64d\n",finds(y,num,p)-finds(x-1,num,p)); 70 } 71 else { 72 scanf("%d%d",&x,&p); 73 if(id[x]==-1) { 74 ax[tp]=x; 75 ac[tp]=p; 76 id[x]=tp; 77 tp++; 78 } 79 else 80 ac[id[x]]=p; 81 } 82 } 83 } 84 return 0; 85 }
用map写的,其他一样
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <map> 4 #include <cstring> 5 using namespace std; 6 const int Ni = 400010; 7 bool isprime[Ni]; 8 map<int,int> mp; 9 int prime[34000],cnt; 10 int factor[30];//素数因子 11 void Prime(){//素数打表 12 cnt=0; 13 memset(isprime,true,sizeof(isprime)); 14 for(int i=2;i<Ni;i++){ 15 if(isprime[i]){ 16 for(int j=i+i;j<Ni;j+=i) 17 isprime[j]=false; 18 prime[cnt++]=i; 19 } 20 } 21 } 22 int gcd(int a,int b){ 23 if(b==0) return a; 24 return gcd(b,a%b); 25 } 26 long long finds(int x,int n,int p){//容斥原理 27 int t,i,j,num,d,m=1<<n; 28 long long ans=(long long)x*(x+1)/2; 29 for(i=1;i<m;i++) { 30 t=i;j=num=0;d=1; 31 while(t) { 32 if(t&1) {d*=factor[j];num++;} 33 j++;t>>=1; 34 } 35 n=x/d; 36 if(num&1) ans-=(long long )d*(1+n)*n/2; 37 else ans+=(long long) d*(1+n)*n/2; 38 } 39 map<int,int>::iterator it; 40 for(it=mp.begin();it!=mp.end();it++) {//处理被改变了的数 41 if(it->first>x) continue; 42 if(gcd(it->first,p)==1) ans-=it->first; 43 if(gcd(it->second,p)==1) ans+=it->second; 44 } 45 return ans; 46 } 47 int pri(int a){//求出a的素数因子 48 if(isprime[a]) {factor[0]=a;return 1;} 49 int k=0,i; 50 for(i=0;i<cnt;i++){ 51 if(a%prime[i]==0) factor[k++]=prime[i]; 52 while(a%prime[i]==0) a/=prime[i]; 53 if(a!=1&&isprime[a]) {factor[k++]=a;return k;} 54 } 55 return k; 56 } 57 int main() 58 { 59 Prime(); 60 int n,m,x,y,op,p,cs; 61 scanf("%d",&cs); 62 while(cs--){ 63 scanf("%d%d",&n,&m); 64 mp.clear(); 65 for(int i=0;i<m;i++){ 66 scanf("%d",&op); 67 if(op==1){ 68 scanf("%d%d%d",&x,&y,&p); 69 int num=pri(p); 70 printf("%I64d\n",finds(y,num,p)-finds(x-1,num,p)); 71 } 72 else { 73 scanf("%d%d",&x,&p); 74 mp[x]=p; 75 } 76 } 77 } 78 return 0; 79 }