BZOJ3813 奇数国

即求区间的乘积的欧拉函数模一个数

预处理前60个素数和逆元,用线段树维护区间乘机和每个素数出现的次数(我用了bitset嗯嗯嗯)

于是可以O(sqrt(n))求出欧拉函数

  1 1
  2 2
  3 3
  4 4
  5 5
  6 6
  7 7
  8 8
  9 9
 10 10
 11 11
 12 12
 13 13
 14 14
 15 15
 16 16
 17 17
 18 18
 19 19
 20 20
 21 21
 22 22
 23 23
 24 24
 25 25
 26 26
 27 27
 28 28
 29 29
 30 30
 31 31
 32 32
 33 33
 34 34
 35 35
 36 36
 37 37
 38 38
 39 39
 40 40
 41 41
 42 42
 43 43
 44 44
 45 45
 46 46
 47 47
 48 48
 49 49
 50 50
 51 51
 52 52
 53 53
 54 54
 55 55
 56 56
 57 57
 58 58
 59 59
 60 60
 61 61
 62 62
 63 63
 64 64
 65 65
 66 66
 67 67
 68 68
 69 69
 70 70
 71 71
 72 72
 73 73
 74 74
 75 75
 76 76
 77 77
 78 78
 79 79
 80 80
 81 81
 82 82
 83 83
 84 84
 85 85
 86 86
 87 87
 88 88
 89 89
 90 90
 91 91
 92 92
 93 93
 94 94
 95 95
 96 96
 97 97
 98 98
 99 99
100 100
101 101
102 102
103 103
104 104
105 105
106 106
107 107
108 108
109 109
110 110
111 111
112 112
113 113
114 114
115 115
116 116
117 117
118 118
119 119
120 120
121 121
122 122
123 123
124 /**************************************************************
125     Problem: 3813
126     User: rausen
127     Language: C++
128     Result: Accepted
129     Time:1644 ms
130     Memory:8624 kb
131 ****************************************************************/
132
133 #include <cstdio>
134 #include <bitset>
135
136 using namespace std;
137 typedef long long ll;
138 const int mod = 19961993;
139 const int N = 1e5 + 5;
140
141 struct segment{
142     ll v;
143     bitset <65> ap;
144 } seg[N << 2];
145
146 int n, m;
147 ll v;
148 bitset <65> ap;
149 int pr[65], tot;
150 ll inv[65];
151 bool vis[305];
152
153 inline int read() {
154     int x = 0;
155     char ch = getchar();
156     while (ch < ‘0‘ || ‘9‘ < ch)
157         ch = getchar();
158     while (‘0‘ <= ch && ch <= ‘9‘) {
159         x = x * 10 + ch - ‘0‘;
160         ch = getchar();
161     }
162     return x;
163 }
164
165 inline ll pow(ll x, int y) {
166     ll res = 1;
167     while (y) {
168         if (y & 1) res = res * x % mod;
169         x = x * x % mod;
170         y >>= 1;
171     }
172     return res;
173 }
174
175 void pre_work() {
176     int i, j;
177     for (i = 2; tot <= 60; ++i)
178         if (!vis[i]) {
179             pr[++tot] = i;
180             for (j = i; j <= 300; j += i) vis[j] = 1;
181         }
182     for (i = 1; i <= 60; ++i)
183         inv[i] = 1ll * pow(pr[i], mod - 2) * (pr[i] - 1) % mod;
184 }
185
186 #define Ls (p << 1)
187 #define Rs (p << 1 | 1)
188 #define mid (l + r >> 1)
189 inline void update(int p) {
190     seg[p].v = seg[Ls].v * seg[Rs].v % mod;
191     seg[p].ap = seg[Ls].ap | seg[Rs].ap;
192 }
193
194 void seg_build(int p, int l, int r) {
195     if (l == r) {
196         seg[p].v = 3, seg[p].ap[2] = 1;
197         return;
198     }
199     seg_build(Ls, l, mid), seg_build(Rs, mid + 1, r);
200     update(p);
201 }
202
203 void seg_modify(int p, int l, int r, int pos, int v) {
204     if (l == r) {
205         int i;
206         seg[p].v = v, seg[p].ap.reset();
207         for (i = 1; i <= 60; ++i)
208             if (v % pr[i] == 0) seg[p].ap[i] = 1;
209         return;
210     }
211     if (pos <= mid) seg_modify(Ls, l, mid, pos, v);
212     else seg_modify(Rs, mid + 1, r, pos, v);
213     update(p);
214 }
215
216 void seg_query(int p, int l, int r, int L, int R) {
217     if (L <= l && r <= R) {
218         v = v * seg[p].v % mod, ap |= seg[p].ap;
219         return;
220     }
221     if (L <= mid) seg_query(Ls, l, mid, L, R);
222     if (mid < R) seg_query(Rs, mid + 1, r, L, R);
223 }
224 #undef mid
225 #undef Ls
226 #undef Rs
227
228 int main() {
229     int oper, x, y, i;
230     pre_work();
231     n = 1e5;
232     seg_build(1, 1, n);
233     m = read();
234     while (m--) {
235         oper = read(), x = read(), y = read();
236         if (oper) seg_modify(1, 1, n, x, y);
237         else {
238             v = 1, ap.reset();
239             seg_query(1, 1, n, x, y);
240             for (i = 1; i <= 60; ++i)
241                 if (ap[i]) v = v * inv[i] % mod;
242             printf("%lld\n", v);
243         }
244     }
245     return 0;
246 }

时间: 2024-12-23 05:32:31

BZOJ3813 奇数国的相关文章

[bzoj3813] 奇数国 [线段树+欧拉函数]

题面 传送门 思路 这题目是真的难读......阅读理解题啊...... 但是理解了以后就发现,题目等价于: 给你一个区间,支持单点修改,以及查询一段区间的乘积的欧拉函数值,这个答案对19961993取模 这里是欧拉函数的原因显然,题目中的那个不相冲实际上就是扩展欧几里得里面的那个定理,要满足不相冲(也就是方程有解),\(product\)和\(number\)必须互质 序列当中,每个元素大小不超过1e6,质因数都是前60个 那么我们显然可以开一棵线段树来维护这个区间乘积,但是怎么处理欧拉函数呢

AC日记——【清华集训2014】奇数国 uoj 38

#38. [清华集训2014]奇数国 思路: 题目中的number与product不想冲: 即为number与product互素: 所以,求phi(product)即可: 除一个数等同于在模的意义下乘以一个数的逆元: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005

2014清华集训 奇数国

3813: 奇数国 Time Limit: 10 Sec  Memory Limit: 256 MBhttp://www.lydsy.com/JudgeOnline/problem.php?id=3813 Description 在一片美丽的大陆上有100000个国家,记为1到100000.这里经济发达,有数不尽的账房,并且每个国家有一个银行.某大公司的领袖在这100000个银行开户时都存了3大洋,他惜财如命,因此会不时地派小弟GFS清点一些银行的存款或者让GFS改变某个银行的存款.该村子在财产

[清华集训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$有关. 所以可以用线段树维护每个区间的乘积,

3813: 奇数国|树状数组|欧拉函数

题目显然让求 φ(∏i=lrai) 可以用线段树维护一下乘积然后求逆元再求欧拉函数,用压位的方法可以缩小60倍的常数.考虑一下树状数组的做法,因为只有60个质因子,所以可以开60个树状数组维护每一个质因子,最初维护了前缀的乘积然后T飞了.因为乘法比起加法还是比较慢的所以可以维护一个前缀的指数和,这样就可以在BZOJ成功卡进最后一页QAQ,然而UOJ的Extra Test还是过不了(应该是我写的代码太丑的原因吧.. #include<algorithm> #include<iostream

BZOJ 3813 奇数国 欧拉函数+线段树+乘法逆元

题目大意:给出一个序列,支持修改操作,求这个序列连续一段的乘积的欧拉函数.每个数的最大质因子不超过281. 思路:φ(n) = n * (1 - 1 / p1) * (1 - 1 / p2) * (1 - 1 / p3) * (1 - 1 / p4)--*(1 - 1 / pn) = n  / (p1 * p2 * p3 * -- * pn) * ((p1 - 1) * (p2 - 1) * (p3 - 1) * -- * (pn - 1)) 于是这个东西只需要维护一下区间中的指数,用bitse

【UOJ#38】【清华集训2014】奇数国

考虑欧拉函数的性质,60很小,压位存下线段树每个节点出现质数. #include<bits/stdc++.h> const int N=100010; const int yql=19961993; typedef long long ll; using namespace std; int prime[100],n,m,vis[910]; ll val,p,rev[100]; struct Segment_Tree{ #define lson (o<<1) #define rso

BZOJ 3813 奇数国 线段树+数论

题目大意:给定一个序列,每个数都由60个最小的素数的乘积构成,求某段的乘积的欧拉函数值对19961993取模后的值,支持单点修改 19961993是个质数 出题人还是满贴心的 利用线段树维护乘积取模后的值以及哪些素数出现过 后者用bitset维护 得到的值根据bitset里出现过的素数来计算欧拉函数值 时间复杂度O(nlog10W+60n) #include <bitset> #include <cstdio> #include <cstring> #include &

HYSBZ 3813 奇数国

题意: 给定一个初始均为3的长度为100000的序列,有m个操作,分为以下两种: ⒈0 x y 设a[x~y]的区间积为sum,求[1~sum]中与sum互质的数的个数 ⒉1 x y 将a[x]变为y 数据保证a[i]<=1000000,且a[i]的唯一分解为的素数为最小的前60个素数(p1=2,p2=3,-,p60=281)题解:①求区间乘积的欧拉函数取模②√n求欧拉函数的方法 ③用两棵线段树,一棵维护乘积,一棵维护质因数(状态压缩,压成一个LL)④预处理乘法逆元和素数 #include <