zoukankan      html  css  js  c++  java
  • [bzoj3813] 奇数国 [线段树+欧拉函数]

    题面

    传送门

    思路

    这题目是真的难读......阅读理解题啊......

    但是理解了以后就发现,题目等价于:

    给你一个区间,支持单点修改,以及查询一段区间的乘积的欧拉函数值,这个答案对19961993取模

    这里是欧拉函数的原因显然,题目中的那个不相冲实际上就是扩展欧几里得里面的那个定理,要满足不相冲(也就是方程有解),$product$和$number$必须互质

    序列当中,每个元素大小不超过1e6,质因数都是前60个

    那么我们显然可以开一棵线段树来维护这个区间乘积,但是怎么处理欧拉函数呢?$O(sqrt{n})$的复杂度求吗?但是这题可以到$1000000^{100000}$诶......

    没关系,我们来看一个神秘小技巧

    设一个数$x=prod_{i=1}{k}p_i{a_i}$,那么:

    $varphi(x)=prod_{i=1}{k}(p_i-1)p_i{a_i-1}=xprod_{i=1}^{k}frac{p_i-1}{p_i}$

    那么我们再开一棵线段树,把60个质因数在对应区间里的出现情况压进一个long long里面

    每次查询的时候,查询出来取模过的乘积,再对每个出现过的质因数乘上模意义下的$frac{p_i-1}{p_i}$,就是答案了

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    #define ll long long
    #define mp make_pair
    using namespace std;
    inline int read(){
    	int re=0,flag=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    const ll MOD=19961993;
    ll qpow(ll a,ll b){
    	ll re=1ll;
    	while(b){
    		if(b&1) re=re*a%MOD;
    		a=a*a%MOD;b>>=1;
    	}
    	return re;
    } 
    int vis[310],pri[70],cntp,inv[70];
    void init(){
    	int i,j,k;vis[1]=1;
    	for(i=2;i<=281;i++){
    		if(!vis[i]) pri[++cntp]=i,inv[cntp]=qpow(i,MOD-2);
    		for(j=1;j<=cntp;j++){
    			k=i*pri[j];if(k>281) break;
    			vis[k]=1;
    			if(i%pri[j]==0) break;
    		}
    	}
    }
    ll a[400010],bit[400010];//a是乘积,b是压位的质因数状态
    void update(int num){
    	int son=num<<1;
    	a[num]=a[son]*a[son+1]%MOD;
    	bit[num]=bit[son]|bit[son+1];
    }
    void build(int l,int r,int num){
    	int mid=(l+r)>>1;
    	if(l==r){
    		a[num]=3;bit[num]=2;return;
    	}
    	build(l,mid,num<<1);build(mid+1,r,(num<<1)+1);
    	update(num);
    }
    void change(int l,int r,int num,int pos,ll val){
    	int mid=(l+r)>>1,i;
    	if(l==r){
    		a[num]=val;bit[num]=0;
    		for(i=1;i<=60;i++) if(val%pri[i]==0) bit[num]|=(1ll<<(i-1));
    		return;
    	}
    	if(mid>=pos) change(l,mid,num<<1,pos,val);
    	else change(mid+1,r,(num<<1)+1,pos,val);
    	update(num);
    }
    pair<ll,ll> query(int l,int r,int ql,int qr,int num){
    	int mid=(l+r)>>1;pair<ll,ll>re=mp(1,0),tmp;
    	if(l>=ql&&r<=qr) return mp(a[num],bit[num]);
    	if(mid>=ql){
    		tmp=query(l,mid,ql,qr,num<<1);
    		re.first=re.first*tmp.first%MOD;
    		re.second|=tmp.second;
    	}
    	if(mid<qr){
    		tmp=query(mid+1,r,ql,qr,(num<<1)+1);
    		re.first=re.first*tmp.first%MOD;
    		re.second|=tmp.second;
    	}
    	return re;
    }
    int main(){
    	int n=read(),i,t1,t2,t3;build(1,100000,1);pair<ll,ll>tmp;
    	init();
    	while(n--){
    		t1=read();t2=read();t3=read();
    		if(t1) change(1,100000,1,t2,t3);
    		else{
    			tmp=query(1,100000,t2,t3,1);
    			for(i=1;i<=60;i++) 
    				if(tmp.second&(1ll<<(i-1)))
    					tmp.first=tmp.first*(pri[i]-1)%MOD*inv[i]%MOD;
    			printf("%lld
    ",tmp.first);
    		}
    	}
    }
    
  • 相关阅读:
    【Django】django 处理request流程细节(转)
    【Django】request 处理流程(转)
    【Django】中间件
    【HTML】DocType
    【CSS】伪类与伪元素
    【nodejs】nodejs 的linux安装(转)
    【chrome】 chrome 开发者工具
    【samba】samba 用户权限配置(转)
    form表单组件
    自定义分页器
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9347985.html
Copyright © 2011-2022 走看看