bzoj3813 奇数国
Description
在一片美丽的大陆上有\(100000\)个国家,记为\(1\)到\(100000\)。这里经济发达,有数不尽的账房,并且每个国家有一个银行。
某大公司的领袖在这\(100000\)个银行开户时都存了\(3\)大洋,他惜财如命,因此会不时地派小弟 GFS 清点一些银行的存款或者让 GFS 改变某个银行的存款。
该村子在财产上的求和运算等同于我们的乘法运算,也就是说领袖开户时的存款总和为\(3^{100000}\)。这里发行的软妹面额是最小的\(60\)个素数(\(p_1=2,p_2=3,\cdots,p_60=281\)),任何人的财产都只能由这\(60\)个基本面额表示,即设某个人的财产为 \(fortune\)(正整数),则\(fortune=p_1^{k_1}p_2^{k_2}\cdots p_{60}^{K_{60}}\)。
领袖习惯将一段编号连续的银行里的存款拿到一个账房去清点,为了避免 GFS 串通账房叛变,所以他不会每次都选择同一个账房。GFS 跟随领袖多年已经摸清了门路,知道领袖选择账房的方式。如果领袖选择清点编号在\([a,b]\)内的银行财产,他会先对\([a,b]\)的财产求和(计为\(product\)),然后在编号属于\([1,product]\)的账房中选择一个去清点存款,检验自己计算是否正确同时也检验账房与 GFS 是否有勾结。
GFS 发现如果某个账房的编号\(number\)与\(product\)相冲,领袖绝对不会选择这个账房。怎样才算与\(product\)不相冲呢?若存在整数\(x,y\)使得\(number\cdot x+product\cdot y=1\),那么我们称\(number\)与\(product\)不相冲,即该账房有可能被领袖相中。
当领袖又赚大钱了的时候,他会在某个银行改变存款,这样一来相同区间的银行在不同的时候算出来的\(product\)可能是不一样的,而且领袖不会在某个银行的存款总数超过\(1000000\)。
现在GFS预先知道了领袖的清点存款与变动存款的计划,想请你告诉他,每次清点存款时领袖有多少个账房可以供他选择,当然这个值可能非常大,GFS只想知道对\(19961993\)取模后的答案。
Input
第一行一个整数\(x\le 10^5\)表示领袖清点和变动存款的总次数。
接下来\(x\)行,每行\(3\)个整数\(a_i,b_i,c_i\)。
- \(a_i\)为\(0\)时表示该条记录是清点计划,领袖会清点\(b_i\)到\(c_i\)的银行存款,你需要对该条记录计算出 GFS 想要的答案。
- \(a_i\)为\(1\)时表示该条记录是存款变动,你要把银行\(b_i\)的存款改为\(c_i\),不需要对该记录进行计算。
Output
输出若干行,每行一个数,表示那些年的答案。
Sample Input
6
0 1 3
1 1 5
0 1 3
1 1 7
0 1 3
0 2 3
Sample Output
18
24
36
6
explanation
初始化每个国家存款都为\(3\);
\(1\)到\(3\)的\(product\)为\(27\),\([1,27]\)与\(27\)不相冲的有\(18\)个数;
\(1\)的存款变为\(5\);
\(1\)到\(3\)的\(product\)为\(45\),\([1,45]\)与\(45\)不相冲的有\(24\)个数;
\(1\)的存款变为\(7\);
\(1\)到\(3\)的\(product\)为\(63\),\([1,63]\)与\(63\)不相冲的有\(36\)个数;
\(2\)到\(3\)的\(product\)为\(9\),\([1,9]\)与\(9\)不相冲的有$64个数。
欧拉函数+线段树
题目里一堆废话,一开始看了样例解释才懂,所以也复制上来了
裴蜀定理告诉我们,题里那个存在整数\(x,y\)使得\(number\cdot x+product\cdot y=1\)成立的条件,其实就是\(\gcd(number,product)=1\)
又由于\(number\le product\),所以其实求的就是\(\varphi(product)\)
所以题目即为:求区间乘积的\(\varphi\)函数取模,并支持单点修改
肯定是要用线段树,维护两个值,一个是区间乘积取模结果,一个是区间乘积有哪些质因数
由于题目告诉我们,不同质因数最多\(60\)个,所以我们用一个\(\texttt{long long}\)的第\(i-1\)个二进制位表示有没有第\(i\)小的质因数
然后合并信息的时候或一下就行,线段树压位常规套路
那么求\(\varphi\)就用到这个公式
所以预处理一下逆元和质数就行了
记得左移的时候要写1ll
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define mod 19961993ll
int n;
struct tr{
tr *ls,*rs;
LL x,p;
}dizhi[200006],*root=&dizhi[0];
int tot;
int prime[305],notprime[305];
LL inv[305];
inline void pre(){
inv[1]=1;
for(reg int i=2;i<=300;i++){
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
if(notprime[i]) continue;
prime[++prime[0]]=i;
for(reg int j=i+i;j<=300;j+=i) notprime[j]=1;
}
}
void build(tr *tree,int l,int r){
if(l==r) return tree->x=3,tree->p=2,void();
int mid=(l+r)>>1;
tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
build(tree->ls,l,mid);build(tree->rs,mid+1,r);
tree->x=tree->ls->x*tree->rs->x%mod;
tree->p=tree->ls->p|tree->rs->p;
}
void change(tr *tree,int l,int r,int pos,int x){
if(l==r){
tree->x=x;
tree->p=0;
for(reg int i=1;i<=prime[0];i++)
if(!(x%prime[i])) tree->p|=1ll<<(i-1);
return;
}
int mid=(l+r)>>1;
if(pos<=mid) change(tree->ls,l,mid,pos,x);
else change(tree->rs,mid+1,r,pos,x);
tree->x=tree->ls->x*tree->rs->x%mod;
tree->p=tree->ls->p|tree->rs->p;
}
void qq(tr *tree,int l,int r,int ql,int qr,LL &x,LL &p){
if(ql<=l&&r<=qr) return x=x*tree->x%mod,p|=tree->p,void();
int mid=(l+r)>>1;
if(ql<=mid) qq(tree->ls,l,mid,ql,qr,x,p);
if(qr>mid) qq(tree->rs,mid+1,r,ql,qr,x,p);
}
int main(){
n=read();
reg int a,b,c;
pre();build(root,1,100000);
while(n--){
a=read();b=read();c=read();
if(a) change(root,1,100000,b,c);
else{
LL x=1,p=0;
qq(root,1,100000,b,c,x,p);
// std::printf("x=%lld p=%lld\n",x,p);
for(reg int i=1;i<=prime[0];i++)
if(p&(1ll<<(i-1))) x=(((x*(prime[i]-1))%mod)*inv[prime[i]])%mod;
std::printf("%lld\n",x);
}
}
// for(reg int i=1;i<=300;i++) std::printf("%d : %lld\n",i,inv[i]);
// std::printf("prime[0]=%d",prime[0]);
return 0;
}