题目大意:给出一个序列,支持修改操作,求这个序列连续一段的乘积的欧拉函数。每个数的最大质因子不超过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;
}