[清华集训2014]奇数国
OJ题号:
UOJ38、BZOJ3813
题目大意:
一个长度为$1000000$的数列,提供以下两种操作:
1.修改某一点的数;
2.求某一区间乘积的欧拉函数。
保证每个元素的最大质因数不超过$281$,答案对$19961933$取模。
思路:
$\varphi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_l})$,其中$p$为$n$的不同的质因数。
可以发现欧拉函数值只与$n$和$p$有关。
所以可以用线段树维护每个区间的乘积,因为$281$是第$60$个质数,因此可以再用一个unsigned long long压位存储每个质数是否出现。
最后套用欧拉函数公式,除法运算相当于乘以逆元。
实现细节:
注意位运算中的1<<i默认是int类型,要转为1ull<<i,否则会WA5个点。
1 #include<map> 2 #include<cmath> 3 #include<cstdio> 4 #include<cctype> 5 #include<vector> 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=1000001,n=1000000,mod=19961993; 14 std::map<int,int> id; 15 inline bool isPrime(const int x) { 16 for(int i=2;i<=floor(sqrt(x));i++) if(!(x%i)) return false; 17 return true; 18 } 19 std::vector<int> v; 20 int inv[282]; 21 class SegmentTree { 22 #define mid ((b+e)>>1) 23 #define _left <<1 24 #define _right <<1|1 25 private: 26 int val[N<<2]; 27 unsigned long long prime[N<<2]; 28 void push_up(const int p) { 29 val[p]=(long long)val[p _left]*val[p _right]%mod; 30 prime[p]=prime[p _left]|prime[p _right]; 31 } 32 std::pair<int,unsigned long long> query(const int p,const int b,const int e,const int l,const int r) { 33 if((b==l)&&(e==r)) return std::make_pair(val[p],prime[p]); 34 std::pair<int,unsigned long long> q1=std::make_pair(1,0),q2=std::make_pair(1,0),ret; 35 if(l<=mid) q1=query(p _left,b,mid,l,std::min(mid,r)); 36 if(r>mid) q2=query(p _right,mid+1,e,std::max(mid+1,l),r); 37 ret.first=(long long)q1.first*q2.first%mod; 38 ret.second=q1.second|q2.second; 39 return ret; 40 } 41 public: 42 void build(const int p,const int b,const int e) { 43 if(b==e) { 44 val[p]=3; 45 prime[p]=2; 46 return; 47 } 48 build(p _left,b,mid); 49 build(p _right,mid+1,e); 50 push_up(p); 51 } 52 void modify(const int p,const int b,const int e,const int x,const int y) { 53 if(b==e) { 54 val[p]=y; 55 prime[p]=0; 56 for(unsigned i=0;i<v.size();i++) { 57 if(!(y%v[i])) prime[p]|=1ull<<i; 58 } 59 return; 60 } 61 if(x<=mid) modify(p _left,b,mid,x,y); 62 if(x>mid) modify(p _right,mid+1,e,x,y); 63 push_up(p); 64 } 65 int phi(const int p,const int b,const int e,const int l,const int r) { 66 std::pair<int,unsigned long long> tmp=query(1,1,n,l,r); 67 int ans=tmp.first; 68 for(unsigned i=0;i<60;i++) { 69 if(tmp.second&(1ull<<i)) { 70 ans=(long long)ans*(v[i]-1)%mod*inv[v[i]]%mod; 71 } 72 } 73 return ans; 74 } 75 }; 76 SegmentTree t; 77 int main() { 78 inv[1]=1; 79 for(int i=2,cnt=0;i<=281;i++) { 80 if(isPrime(i)) { 81 id[i]=cnt++; 82 v.push_back(i); 83 } 84 inv[i]=(long long)(mod-mod/i)*inv[mod%i]%mod; 85 } 86 int x=getint(); 87 t.build(1,1,n); 88 for(int i=1;i<=x;i++) { 89 int a=getint(),b=getint(),c=getint(); 90 if(a) { 91 t.modify(1,1,n,b,c); 92 } 93 else { 94 printf("%d\n",t.phi(1,1,n,b,c)); 95 } 96 } 97 return 0; 98 }
事实上质数只有60个,所以可以直接打表。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 char ch; 6 while(!isdigit(ch=getchar())); 7 int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=1000001,n=1000000,mod=19961993; 12 const int v[60]={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}; 13 const int inv[60]={9980997,6653998,11977196,8555140,5444180,1535538,10568114,14708837,3471651,11701858,17386252,1618540,16066970,2321162,18263100,16948862,12518538,15380552,10725847,1686929,13399146,17182475,12025297,15924736,13582387,395287,6395590,15857658,16299242,6359573,3300802,18742940,6702567,10914471,16210746,11765678,5340151,18247466,7769638,8077107,11932588,6506948,1985748,6619521,5877135,4413707,9744480,10115270,14597757,16475182,18334191,5011379,18885205,7555336,621385,11309266,12170137,12006660,18304499,11153142}; 14 class SegmentTree { 15 #define mid ((b+e)>>1) 16 #define _left <<1 17 #define _right <<1|1 18 private: 19 int val[N<<2]; 20 unsigned long long prime[N<<2]; 21 void push_up(const int p) { 22 val[p]=(long long)val[p _left]*val[p _right]%mod; 23 prime[p]=prime[p _left]|prime[p _right]; 24 } 25 std::pair<int,unsigned long long> query(const int p,const int b,const int e,const int l,const int r) { 26 if((b==l)&&(e==r)) return std::make_pair(val[p],prime[p]); 27 std::pair<int,unsigned long long> q1=std::make_pair(1,0),q2=std::make_pair(1,0),ret; 28 if(l<=mid) q1=query(p _left,b,mid,l,std::min(mid,r)); 29 if(r>mid) q2=query(p _right,mid+1,e,std::max(mid+1,l),r); 30 ret.first=(long long)q1.first*q2.first%mod; 31 ret.second=q1.second|q2.second; 32 return ret; 33 } 34 public: 35 void build(const int p,const int b,const int e) { 36 if(b==e) { 37 val[p]=3; 38 prime[p]=2; 39 return; 40 } 41 build(p _left,b,mid); 42 build(p _right,mid+1,e); 43 push_up(p); 44 } 45 void modify(const int p,const int b,const int e,const int x,const int y) { 46 if(b==e) { 47 val[p]=y; 48 prime[p]=0; 49 for(unsigned i=0;i<60;i++) { 50 if(!(y%v[i])) prime[p]|=1ull<<i; 51 } 52 return; 53 } 54 if(x<=mid) modify(p _left,b,mid,x,y); 55 if(x>mid) modify(p _right,mid+1,e,x,y); 56 push_up(p); 57 } 58 int phi(const int p,const int b,const int e,const int l,const int r) { 59 std::pair<int,unsigned long long> tmp=query(1,1,n,l,r); 60 int ans=tmp.first; 61 for(unsigned i=0;i<60;i++) { 62 if(tmp.second&(1ull<<i)) { 63 ans=(long long)ans*(v[i]-1)%mod*inv[i]%mod; 64 } 65 } 66 return ans; 67 } 68 }; 69 SegmentTree t; 70 int main() { 71 t.build(1,1,n); 72 for(int x=getint();x;x--) { 73 int a=getint(),b=getint(),c=getint(); 74 if(a) { 75 t.modify(1,1,n,b,c); 76 } 77 else { 78 printf("%d\n",t.phi(1,1,n,b,c)); 79 } 80 } 81 return 0; 82 }