P4140 奇数国

P4140

先打质数表
#include<cstdio>
#include<cmath>
using namespace std;
bool shai(int n){
	if(n < 2) return false;
	int b = sqrt(n);
	for(int i=2;i<=b;i++)
	if(n % i == 0) return false;
	return true;
}
int main(){
	for(int i=1;i<=282;i++)
	if(shai(i) == true)
	printf("%d ",i);
}
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

一个地方总数不超100w 0区间乘,和区间查询
1是单点修改 num编号 pro区间积 num整数+pro整数=1
\(转化为gcd(pro,num)=1\)

也就是说\([1,N]\)里多少\(num\)\(product\)互质,即\(φ(product)\)等于多少

\[φ(N)=n*\prod_{质数p_i|n}(1-\frac{1}{p_i})=\prod_{p_i|n}p^k-p^{k-1}=n*\prod_{p_i|n}\frac{p_i-1}{p_i}\\ 证明其实很简单~~唯一分解定理显然 \]

看数据范围\(mod~p\),所以再线性推逆元

	ny[1]=1;
	for(int i=2;i<=281;i++)
	ny[i]=(long long)(mod-mod/i)*ny[mod%i]%mod;

区间维护:

维护区间积 , 单点修改

因为最多60个质数,把它们压在\(long~~long\)里 ,\(or\)相当于相乘操作

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define mod 19961993
const int prime[61]={
	0,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
};
int pni[300];
	struct data{
		long long sum;//区间(和)乘积 
		long long p;//包含哪些素数。第i个二进制位如果是1,则有prime[i]这个素数,从1开始。 
	}point[400010];
	data ans;//记录查询答案。
	void built(int l,int r,int o)
	{
		if(l==r) {point[o].sum=3;point[o].p=2;return ;}
		int mid=(l+r)/2;
		built(l,mid,o*2);
		built(mid+1,r,o*2+1);		
		point[o].sum=point[o*2].sum*point[o*2+1].sum%mod;
		point[o].p=2;
	}	
	void chang(int l,int r,int o,const int t,const int k)//第t个点改为k 
	{
		if(l==r){
			point[o].sum=k;
			long long p=0;
			for(int i=1;i<=60;i++){
				if((k%prime[i])==0) p|=1LL<<(i-1);
				point[o].p=p;
			}
			return ;
		}
		int mid=(l+r)/2;
		if(t<=mid) chang(l,mid,o*2,t,k);
		else chang(mid+1,r,o*2+1,t,k);
		point[o].sum=point[o*2].sum*point[o*2+1].sum%mod;
		point[o].p=point[o*2].p|point[o*2+1].p;
	}
	void quest(int l,int r,int o,int l1,int r1)//查询L到R。 
	{
		if(l1<=l&&r<=r1){
			ans.sum=ans.sum*point[o].sum%mod;
			ans.p|=point[o].p;
			return ;
		}
		int mid=(l+r)/2;
		if(l1<=mid) quest(l,mid,o*2,l1,r1);
		if(mid<r1)  quest(mid+1,r,o*2+1,l1,r1);
	} 
int main()
{
	built(1,100000,1);
	pni[1]=1;
	for(int i=2;i<=281;i++)
	pni[i]=(long long)(mod-mod/i)*pni[mod%i]%mod;
	int tt;
	scanf("%d",&tt);
	while(tt--)
	{
		int x;scanf("%d",&x);
	
		if(x)
		{
		int t,k;
		scanf("%d%d",&t,&k);
		chang(1,100000,1,t,k);
		}
		else
		{
			int l1,r1;
			ans.sum=1;
			ans.p=0;
			scanf("%d%d",&l1,&r1);
			quest(1,100000,1,l1,r1);
		
			long long f=ans.sum;
			for(int i=1;i<=60;i++)//计算φ 
			if(ans.p&(1LL<<(i-1))) f=f*(prime[i]-1)%mod,f=f*pni[prime[i]]%mod;
			printf("%d\n",(int)f);
		}
	}
	return 0;
}

posted @ 2020-07-22 21:22  INFP  阅读(117)  评论(0编辑  收藏  举报