• 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)使得(numbercdot x+productcdot y=1),那么我们称(number)(product)不相冲,即该账房有可能被领袖相中。

    当领袖又赚大钱了的时候,他会在某个银行改变存款,这样一来相同区间的银行在不同的时候算出来的(product)可能是不一样的,而且领袖不会在某个银行的存款总数超过(1000000)
    现在GFS预先知道了领袖的清点存款与变动存款的计划,想请你告诉他,每次清点存款时领袖有多少个账房可以供他选择,当然这个值可能非常大,GFS只想知道对(19961993)取模后的答案。

    Input

    第一行一个整数(xle 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)使得(numbercdot x+productcdot y=1)成立的条件,其实就是(gcd(number,product)=1)
    又由于(numberle product),所以其实求的就是(varphi(product))
    所以题目即为:求区间乘积的(varphi)函数取模,并支持单点修改


    肯定是要用线段树,维护两个值,一个是区间乘积取模结果,一个是区间乘积有哪些质因数
    由于题目告诉我们,不同质因数最多(60)个,所以我们用一个( exttt{long long})的第(i-1)个二进制位表示有没有第(i)小的质因数
    然后合并信息的时候或一下就行,线段树压位常规套路

    那么求(varphi)就用到这个公式

    [varphi(n)=nprod frac{p_i-1}{p_i},p_iin prime,p_imid n ]

    所以预处理一下逆元和质数就行了
    记得左移的时候要写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
    ",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
    ",x);
    		}
    	}
    //		for(reg int i=1;i<=300;i++) std::printf("%d : %lld
    ",i,inv[i]);
    //		std::printf("prime[0]=%d",prime[0]);
    	return 0;
    }
    
  • 相关阅读:
    为什么我的从任务管理器中看见我的硬盘使用率是100%(2)
    为什么我的从任务管理器中看见我的硬盘使用率是100%(1)
    win8正式版
    pwnable_orw
    cmcc_simplerop
    分析kernel.dll函数CreateRemoteThread进0环
    [V&N2020 公开赛]easyTHeap
    恶意代码分析训练第一天
    SWPUCTF_2019_p1KkHeap
    3环函数进入0环函数
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12657215.html
Copyright © 2020-2023  润新知