zoukankan      html  css  js  c++  java
  • 奇数国题解

    原题
    虽然 (ntf) 学长嘲讽了这道题,但我认为这道题很适合我(菜鸡)了解线段树的有趣用法
    首先翻译题面,就是每次进行一个操作——询问一个区间内所有数的乘积的欧拉函数或者修改数列中的一个数
    由于每个数上限是(10^6),暴力求完一个区间的乘积再套欧拉函数是不可能的
    首先了解先欧拉函数的公式

    [φ(x)=x*prod_{i|x且i为质数}^{}{(1-frac{1}{i})} ]

    看到这个公式,发现我们其实没有必要求出区间数的乘积,我们只需要知道这个乘积里会有几个不同的质数就可以了
    然后每个数不超过(10^6),所以会出现的质数不超过(60)个,可以状态压缩
    用一个(f)数组记录取模后的区间乘积,用一个(ff)记录区间内出现的质数种类的状压,每次查询一个区间的这两个值就能求出这个区间乘积的欧拉函数
    下面说下具体过程,不想剧透的小伙伴可以开始敲代码了

    • 1、对于每个修改操作,分解出这个数的每个质因数,并状压
    • 2、对于查询,首先求出区间积(公式里的x)
    • 3、查询这个区间质因数种类的状压数字,还原出有哪些质因数
    • 4、用第二步和第三步求出的值直接求欧拉函数
      时间复杂度为(O(60*n*log(len)))
      下面AC代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define mid ((l+r)/2)
    #define ll long long
    using namespace std;
    const ll P[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281};
    const ll inv[]={9980997,6653998,11977196,8555140,5444180,1535538,10568114,14708837,3471651,11701858,17386252,1618540,16066970,2321162,18263100,16948862,12518538,15380552,10725847,1686929,13399146,17182475,12025297,15924736,13582387,395287,6395590,15857658,16299242,6359573,3300802,18742940,6702567,10914471,16210746,11765678,5340151,18247466,7769638,8077107,11932588,6506948,1985748,6619521,5877135,4413707,9744480,10115270,14597757,16475182,18334191,5011379,18885205,7555336,621385,11309266,12170137,12006660,18304499,11153142};
    const ll mod=19961993;
    ll n,f[8000010],ff[8000010];
    
    void build(ll l,ll r,ll o){
    	if(l==r){
    		f[o]=2,ff[o]=3;
    		return ;
    	}
    	build(l,mid,o*2);
    	build(mid+1,r,o*2+1);
    	f[o]=f[o*2]|f[o*2+1];
    	ff[o]=ff[o*2]*ff[o*2+1]%mod;
    }
    
    void modify(ll l,ll r,ll o,ll x,ll d,ll d2){
    	if(l==r){
    		f[o]=d,ff[o]=d2;
    		return ;
    	}
    	if(x<=mid)modify(l,mid,o*2,x,d,d2);
    	else modify(mid+1,r,o*2+1,x,d,d2);
    	f[o]=f[o*2]|f[o*2+1];
    	ff[o]=ff[o*2]*ff[o*2+1]%mod;
    }
    
    ll Query(ll l,ll r,ll o,ll i,ll j){
    	if(i<=l&&r<=j){
    		return ff[o];
    	}
    	ll ret=1;
    	if(i<=mid)ret=ret*Query(l,mid,o*2,i,j)%mod;
    	if(mid<j)ret=ret*Query(mid+1,r,o*2+1,i,j)%mod;
    	return ret;
    }
    
    ll query(ll l,ll r,ll o,ll i,ll j){
    	if(i<=l&&r<=j){
    		return f[o];
    	}
    	ll ret=0;
    	if(i<=mid)ret|=query(l,mid,o*2,i,j);
    	if(mid<j)ret|=query(mid+1,r,o*2+1,i,j);
    	return ret;
    }
    
    ll pre_work(ll x){
    	ll tmp=0;
    	for(ll i=0;i<60;i++){
    		if(x%P[i]==0)tmp|=(1ll<<i);
    	}
    	return tmp;
    }
    
    int main(){
    	cin>>n;
    	for(ll i=1;i<=100000;i++)modify(1,100000,1,i,2,3);
    	while(n--){
    		ll opt,a1,a2;
    		scanf("%lld%lld%lld",&opt,&a1,&a2);
    		if(opt==1)modify(1,100000,1,a1,pre_work(a2),a2);
    		else {
    			ll tmp=query(1,100000,1,a1,a2);
    			ll ans=Query(1,100000,1,a1,a2);
    			for(ll i=0,a1;i<60;i++){
    				if(tmp&(1ll<<i)){
    					ans=(ans*inv[i])%mod,ans=(ans*(P[i]-1))%mod;
    				}
    			}
    			printf("%lld
    ",ans);
    		}
    	}
    }
    
  • 相关阅读:
    Codeforces Beta Round #6 (Div. 2 Only)
    Codeforces Beta Round #5
    Codeforces Beta Round #4 (Div. 2 Only)
    Codeforces Beta Round #3
    Codeforces Beta Round #2
    Codeforces Beta Round #1
    HDU 4020 Ads Proposal
    SRM 615 DIV1 500
    求1+2+……+n(位运算)
    好好加油!
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/14044599.html
Copyright © 2011-2022 走看看