zoukankan      html  css  js  c++  java
  • 【YbtOJ#911】欧拉函数

    题目

    题目链接:https://www.ybtoj.com.cn/contest/125/problem/1

    (nleq 50000;Qleq 10^5;a_i,xleq 40000),除了操作编号,其余数据全部随机。时限 (3.5s)

    思路

    数据随机,考虑乱搞。
    首先需要一个线段树维护区间和以及区间乘积 (mod 10^9+7)


    对于操作一,区间和 (leq 2 imes 10^9),考虑 洛谷P5071 [Ynoi2015] 此时此刻的光辉 的套路,因为 (1300^3>2 imes 10^9),我们直接暴力求出这个数 (1300) 内的质因子,然后剩余最多两个超过 (1300) 的质因子,用 Pollard-Rho 求出其中一个,另外一个除一下就出来了。
    这部分的单次复杂度为 (O(log n+1300+ ext{PR 玄学复杂度}))。忽略掉 PR 的复杂度以及常数的话,极限大约需要执行 131,600,000 次。


    对于操作二,因为是区间乘积,所以保证了这个数的所有质因子都是不超过 (40000) 的。考虑直接暴力求出所有的质因子。
    在线段树上每一个节点维护一个 bitset,表示这个区间的数的质因子集合。然后每次直接把 ([l,r]) 的 bitset 暴力合并。
    接下来直接无脑暴力枚举所有不超过 (40000) 的质数((4202) 个),然后更新答案即可。
    这部分单词时间复杂度为 (O(log nlog 40000+4202)),忽略常数极限大约需要执行 445,800,000 次。

    但是由于这道题数据随机,所以实际上常数非常小。可以通过。
    正解是复杂度 (O((n+Q)klog^2 n)) 的二维数点,其中 (k) 是一个数不同的质因子数量。

    代码

    怎么看我这个都比正解长。。。

    #include <bits/stdc++.h>
    #define reg register
    using namespace std;
    typedef long long ll;
    
    const int N=50010,M=4206,Lim=2000,MOD=1e9+7;
    const int prime[3]={2,7,61};
    int n,m,Q,maxd,a[N],prm[N],inv[N],id[N];
    bool v[N];
    bitset<M> g,f[N];
    
    int gcd(int x,int y)
    {
    	return y?gcd(y,x%y):x;
    }
    
    int fpow(int x,int k,int mod=MOD)
    {
    	int ans=1;
    	for (;k;k>>=1,x=1LL*x*x%mod)
    		if (k&1) ans=1LL*ans*x%mod;
    	return ans;
    }
    
    void findprm(int n)
    {
    	for (reg int i=2;i<=n;i++)
    		if (!v[i])
    		{
    			prm[++m]=i; id[i]=m;
    			inv[m]=fpow(i,MOD-2)%MOD;
    			for (reg int j=1;j*i<=n;j++)
    				v[j*i]=1;
    		}
    }
    
    void getfac(int n)
    {
    	for (reg int i=1;i<=n;i++)
    	{
    		int p=i;
    		for (reg int j=1;prm[j]*prm[j]<=p;j++)
    			if (!(p%prm[j]))
    			{
    				f[i][j]=1;
    				while (!(p%prm[j])) p/=prm[j];
    			}
    		if (p>1) f[i][id[p]]=1;
    	}
    }
    
    struct SegTree
    {
    	int sum[N*4],mul[N*4];
    	bitset<M> d[N*4];
    	
    	void pushup(int x)
    	{
    		d[x]=d[x*2]|d[x*2+1];
    		sum[x]=sum[x*2]+sum[x*2+1];
    		mul[x]=1LL*mul[x*2]*mul[x*2+1]%MOD;
    	}
    	
    	void update(int x,int l,int r,int k,int v)
    	{
    		if (l==r)
    		{
    			d[x].reset(); d[x]|=f[v];
    			sum[x]=mul[x]=v;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if (k<=mid) update(x*2,l,mid,k,v);
    			else update(x*2+1,mid+1,r,k,v);
    		pushup(x);
    	}
    	
    	int query1(int x,int l,int r,int ql,int qr)
    	{
    		if (ql<=l && qr>=r) return sum[x];
    		int mid=(l+r)>>1,res=0;
    		if (ql<=mid) res+=query1(x*2,l,mid,ql,qr);
    		if (qr>mid) res+=query1(x*2+1,mid+1,r,ql,qr);
    		return res;
    	}
    	
    	int query2(int x,int l,int r,int ql,int qr)
    	{
    		if (ql<=l && qr>=r)
    		{
    			g|=d[x];
    			return mul[x];
    		}
    		int mid=(l+r)>>1,res=1;
    		if (ql<=mid) res=1LL*res*query2(x*2,l,mid,ql,qr)%MOD;
    		if (qr>mid) res=1LL*res*query2(x*2+1,mid+1,r,ql,qr)%MOD;
    		return res;
    	}
    }seg;
    
    bool MR(int n)
    {
    	for (reg int i=0;i<=2;i++)
    	{
    		if (n==prime[i]) return 1;
    		int p=n-1,pw=fpow(prime[i],p,n);
    		while (pw==1 && !(p&1))
    			p>>=1,pw=fpow(prime[i],p,n);
    		if (pw!=1 && pw!=n-1) return 0;
    	}
    	return 1;
    }
    
    int work(int n)
    {
    	int s=0,t=0,c=rand()%(n-1)+1,val=1,lim=2;
    	for (reg int i=1;;i++)
    	{
    		t=(1LL*t*t+c)%n; val=1LL*val*abs(s-t)%n;
    		if (i==lim || !(i%127))
    		{
    			int d=gcd(n,val);
    			if (d>1) return d;
    			if (i==lim) s=t,val=1,lim<<=1;
    		}
    	}
    	return 19260817;
    }
    
    void PR(int n)
    {
    	if (n<maxd || n<2) return;
    	if (MR(n)) { maxd=n; return; }
    	int p=work(n);
    	while (p>=n) p=work(n);
    	while (!(n%p)) n/=p;
    	PR(n); PR(p);
    }
    
    int main()
    {
    	freopen("phi.in","r",stdin);
    	freopen("phi.out","w",stdout);
    	srand('Q'+'u'+'a'+'n'+'t'+'A'+'s'+'k'+'A'+'K'+'I'+'O'+'I');
    	findprm(40000);
    	getfac(40000);
    	scanf("%d%d",&n,&Q);
    	for (reg int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		seg.update(1,1,n,i,a[i]);
    	}
    	while (Q--)
    	{
    		int opt,l,r;
    		scanf("%d%d%d",&opt,&l,&r);
    		if (opt==0)
    		{
    			seg.update(1,1,n,l,r);
    			a[l]=r;
    		}
    		if (opt==1)
    		{
    			int sum=seg.query1(1,1,n,l,r),phi=sum;
    			for (reg int i=1;prm[i]<=1300;i++)
    				if (!(sum%prm[i]))
    				{
    					phi=phi/prm[i]*(prm[i]-1);
    					while (!(sum%prm[i])) sum/=prm[i];
    				}
    			if (sum>1)
    			{
    				maxd=0; PR(sum);
    				phi=phi/maxd*(maxd-1);
    				if (1LL*maxd*maxd!=sum && maxd!=sum)
    					phi=phi/(sum/maxd)*(sum/maxd-1);
    			}
    			printf("%d
    ",phi);
    		}
    		if (opt==2)
    		{
    			g.reset();
    			int mul=seg.query2(1,1,n,l,r);
    			for (reg int i=1;i<M;i++)
    				if (g[i]) mul=1LL*mul*inv[i]%MOD*(prm[i]-1)%MOD;
    			printf("%d
    ",mul);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Nokia Lumia 800销售反馈 苹果iPhone、三星Galaxy不敌800设计
    各大网站用户数据库被爆,遭大量网友下载
    最美发明家:GPS、手机通讯网都源自她的发明
    iPhone5或明年下半年发布 配备iOS6和A6芯片
    保存文件到手机内存
    2012年十大科技趋势:NFC、语音控制与弯曲屏
    电脑报独家报道:宽带升级全国真相调查
    Android的电话拨号器
    Java程序员成长之路(接口与抽象类究竟有什么区别)
    联系人相关
  • 原文地址:https://www.cnblogs.com/stoorz/p/14453237.html
Copyright © 2011-2022 走看看