奇数国
大半夜罗了奇怪的做法,发现M啦QAQ,内心死亡,然而第二天早上写完另一种发现交的代码是nn=4,内心死亡again
首先从题意分析就是,线段树上罗,然后求欧拉函数
两种做法的区别在于求的公式不同
第一种是,phi(x)=sigma(pn-1)pn^(an-1),其中pn为对x分解质因数
这种做法需要记录每个因数的个数,所以奇慢
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define lson rt<<1,l,mid 5 #define rson rt<<1|1,mid+1,r 6 #define maxn 100005 7 #define mod 19961993 8 typedef long long i64; 9 struct node{ 10 int v[61]; 11 void clear(){memset(v,0,sizeof(v));} 12 node operator+(const node &t)const{ 13 node tmp; 14 tmp.v[0]=0;// 15 for(int i=1;i<=60;i++) 16 tmp.v[i]=v[i]+t.v[i]; 17 return tmp; 18 } 19 20 }tree[maxn<<2],tmp; 21 i64 prime[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281}; 22 int nn=100000; 23 int read(){ 24 int haha=0; 25 char ch=0; 26 while(!isdigit(ch))ch=getchar(); 27 while(isdigit(ch)){ 28 haha=haha*10+ch-'0'; 29 ch=getchar(); 30 } 31 return haha; 32 } 33 node div(int x){ 34 node t; 35 t.v[0]=0;// 36 for(int i=1;i<=60;i++){ 37 t.v[i]=0; 38 while(x&&x%prime[i]==0) 39 t.v[i]++,x/=prime[i]; 40 } 41 return t; 42 } 43 void update(int rt,int l,int r,int pos,int x){ 44 if(l==r){ 45 tree[rt]=div(x); 46 return; 47 } 48 int mid=(l+r)>>1; 49 if(pos<=mid)update(lson,pos,x); 50 else update(rson,pos,x); 51 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; 52 } 53 void query(int rt,int l,int r,int ql,int qr){ 54 if(ql<=l&&qr>=r){ 55 tmp=tmp+tree[rt]; 56 return; 57 } 58 int mid=(l+r)>>1; 59 if(ql<=mid)query(lson,ql,qr); 60 if(qr>mid)query(rson,ql,qr); 61 } 62 i64 qp(i64 bs,int x){ 63 i64 ans=1; 64 while(x){ 65 if(x&1)ans=(ans*bs)%mod; 66 bs=(bs*bs)%mod; 67 x>>=1; 68 } 69 return ans; 70 } 71 int main(){ 72 for(int i=1;i<=nn;i++) 73 update(1,1,nn,i,3); 74 int n,op,a,b; 75 n=read(); 76 for(int i=1;i<=n;i++){ 77 op=read(),a=read(),b=read(); 78 if(!op){ 79 tmp.clear(); 80 query(1,1,nn,a,b); 81 i64 ans=1LL; 82 for(int j=1;j<=60;j++) 83 if(tmp.v[j]) 84 ans=(ans*((prime[j]-1)*qp(prime[j],tmp.v[j]-1))%mod)%mod; 85 printf("%lld\n",ans);// 86 } 87 else update(1,1,nn,a,b); 88 } 89 return 0; 90 }
第二种是phi(x)=x*(p1-1)/p1*(p2-1)/p2*...*(pn-1)/pn
这玩意只需要知道x的因数有哪些,可以压到一个long long里,因为有除法,所以会用到乘法逆元
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long i64; 5 #define lson rt<<1,l,mid 6 #define rson rt<<1|1,mid+1,r 7 #define mod 19961993 8 #define maxn 100005 9 const int nn=100000; 10 i64 prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281}; 11 i64 am,ap,pri[maxn<<2],mul[maxn<<2],ni[60]; 12 13 int read(){ 14 int tmp=0; 15 char ch=0; 16 while(!isdigit(ch))ch=getchar(); 17 while(isdigit(ch)){ 18 tmp=tmp*10+ch-'0'; 19 ch=getchar(); 20 } 21 return tmp; 22 } 23 i64 div(int x){ 24 i64 haha=0; 25 for(int i=0;i<60;i++) 26 if(x%prime[i]==0)haha|=(1LL<<i); 27 return haha; 28 } 29 void update(int rt,int l,int r,int pos,int x){ 30 if(l==r){ 31 mul[rt]=x%mod; 32 pri[rt]=div(x); 33 return; 34 } 35 int mid=(l+r)>>1; 36 if(pos<=mid)update(lson,pos,x); 37 else update(rson,pos,x); 38 mul[rt]=(mul[rt<<1]*mul[rt<<1|1])%mod; 39 pri[rt]=pri[rt<<1]|pri[rt<<1|1]; 40 } 41 void query(int rt,int l,int r,int ql,int qr){ 42 if(ql<=l&&qr>=r){ 43 am=(am*mul[rt])%mod; 44 ap|=pri[rt]; 45 return; 46 } 47 int mid=(l+r)>>1; 48 if(ql<=mid)query(lson,ql,qr); 49 if(qr>mid)query(rson,ql,qr); 50 } 51 i64 qp(i64 bs,int x){ 52 i64 sum=1LL; 53 while(x){ 54 if(x&1)sum=(sum*bs)%mod; 55 bs=(bs*bs)%mod; 56 x>>=1; 57 } 58 return sum; 59 } 60 int main(){ 61 for(int i=0;i<60;i++) 62 ni[i]=qp(prime[i],mod-2); 63 for(int i=1;i<=nn;i++) 64 update(1,1,nn,i,3); 65 int n,op,a,b; 66 n=read(); 67 for(int i=1;i<=n;i++){ 68 op=read(),a=read(),b=read(); 69 if(!op){ 70 am=1LL,ap=0; 71 query(1,1,nn,a,b); 72 for(int j=0;j<60;j++) 73 if(ap&(1LL<<j))am=(am*((prime[j]-1)*ni[j])%mod)%mod; 74 printf("%lld\n",am); 75 } 76 else update(1,1,nn,a,b); 77 } 78 return 0; 79 }