[清华集训2014]奇数国

Posted skylee的OI博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[清华集训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 }
View Code

 

以上是关于[清华集训2014]奇数国的主要内容,如果未能解决你的问题,请参考以下文章

[清华集训2014]奇数国

UOJ#38清华集训2014奇数国

[清华集训2014]奇数国

清华集训2014 做题记录

奇数国[清华集训2014 Day1]

清华集训 2014--奇数国(线段树&欧拉函数&乘法逆元&状态压缩)