首页 > 代码库 > BZOJ 3813 奇数国 欧拉函数+线段树+乘法逆元
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))
于是这个东西只需要维护一下区间中的指数,用bitset维护一下质因数,出发就用一下乘法逆元,没了。。
CODE:
#include <bitset> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define P 19961993 #define MAX 100010 using namespace std; #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define max(a,b) ((a) > (b) ? (a):(b)) struct Ask{ int flag,x,y; void Read() { scanf("%d%d%d",&flag,&x,&y); } }ask[MAX]; struct SegTree{ bitset<61> prime; int total; SegTree(bitset<61> _,int __):prime(_),total(__) {} SegTree() {} SegTree operator +(const SegTree &a)const { return SegTree(prime|a.prime,(long long)total * a.total % P); } }tree[MAX << 2]; int G[300],g[300]; long long inv[300]; int asks,cnt; inline bool Judge(int x) { for(int i = 2; i * i <= x; ++i) if(x % i == 0) return false; return true; } void Shake() { inv[1] = 1; for(int i = 2; i <= 281; ++i) inv[i] = (P - P / i) * inv[P % i] % P; } void Pretreatment() { Shake(); int cnt = 0; for(int i = 2; i <= 281; ++i) if(Judge(i)) G[i] = ++cnt,g[cnt] = i; } void BuildTree(int l,int r,int pos) { if(l == r) { tree[pos].prime[G[3]] = 1; tree[pos].total = 3; return ; } int mid = (l + r) >> 1; BuildTree(l,mid,LEFT); BuildTree(mid + 1,r,RIGHT); tree[pos] = tree[LEFT] + tree[RIGHT]; } SegTree Ask(int l,int r,int x,int y,int pos) { if(l == x && r == y) return tree[pos]; int mid = (l + r) >> 1; if(y <= mid) return Ask(l,mid,x,y,LEFT); if(x > mid) return Ask(mid + 1,r,x,y,RIGHT); SegTree left = Ask(l,mid,x,mid,LEFT); SegTree right = Ask(mid + 1,r,mid + 1,y,RIGHT); return left + right; } void Modify(int l,int r,int x,int pos,SegTree c) { if(l == r) { tree[pos] = c; return ; } int mid = (l + r) >> 1; if(x <= mid) Modify(l,mid,x,LEFT,c); else Modify(mid + 1,r,x,RIGHT,c); tree[pos] = tree[LEFT] + tree[RIGHT]; } int main() { Pretreatment(); cin >> asks; for(int i = 1; i <= asks; ++i) ask[i].Read(); cnt = MAX - 1; BuildTree(1,cnt,1); for(int flag,x,y,i = 1; i <= asks; ++i) { flag = ask[i].flag; x = ask[i].x,y = ask[i].y; if(flag) { bitset<61> p; for(int j = 1; j <= 60; ++j) if(y % g[j] == 0) p[j] = 1; SegTree c(p,y); Modify(1,cnt,x,1,c); } else { SegTree ans = Ask(1,cnt,x,y,1); for(int j = 1; j <= 60; ++j) if(ans.prime[j]) { ans.total = ((long long)ans.total * inv[g[j]]) % P; ans.total = ((long long)ans.total * (g[j] - 1)) % P; } printf("%d\n",ans.total); } } return 0; }
BZOJ 3813 奇数国 欧拉函数+线段树+乘法逆元
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。