2018/07/07测试T3 好数

【题目】

题目描述:

我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:
1. 这个数是 0 或 1 。

2. 所有小于这个数且与它互质的正整数可以排成一个等差数列,例如,8 就是一个好数,因为 1,3,5,7 排成了等差数列。

给出 N 个非负整数,然后进行如下三个操作:

1. 询问区间 [L,R] 有多少个好数。
2. 将区间 [L,R] 内所有数对 S 取余(S≤1000000)。

3. 将第 C 个数更改为 X 。

提示:如果你不知道如何判断一个数是否为好数,你可以打个表找找规律。

输入格式:

第一行包含两个正整数 N 和 M ,M 表示操作数目。
第二行包含 N 个非负整数。

接下来的 M 行每行表示 1 个操作:“1 L R”表示第 1 个操作,“2 L R S”表示第 2 个操作,“3 C X”表示第 3 个操作。

输出格式:

对每个操作1,输出一个非负整数,表示区间内好数的个数。

样例数据:

输入
3 6 
4 6 9 
1 1 3 
1 3 3 
2 1 1 10 
1 1 3 
3 2 4 
1 1 3
输出




2

输入
8 5 
12 24 17 31 16 21 18 30 
1 2 5 
2 4 7 7 
3 2 13 
1 1 8 
1 3 6
输出



4


备注:

数据规模与约定:


【分析】

首先我们分析一下哪些数是好数,我是先打了一个表(100以内):

0 1 3 4 5 6 7 8 11 13 16 17 19 23 29 31 32 37 41 43 47 53 59 61 64 67 71 73 79 83 89 97 

这样还是不好找规律,我们再重新排一下:

0 1
2 4 6 8 16 32 64 

3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

这样一来,我们发现0、1、6、质数、2的k次幂的数都是好数

然后我们就可以做题了

首先,若没有2操作,那么我们可以直接用线段树来做

但加上2操作之后,用线段树貌似就不妥了

这个时候,我们就需要知道一个东西每个数取余后要么不变化,要么小于它的1/2

然后我们就又可以用线段树来做了~~~

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005,M=1000005;
int n,m;
int a[N],sum[4*N],maxn[4*N],prime[M];
bool mark[M];
void init()
{
	int i,j,sum=0;
	memset(mark,true,sizeof(mark));
	for(i=2;i<=M;++i)
	{
		if(mark[i])  prime[++sum]=i;
		for(j=1;j<=sum&&i*prime[j]<=M;++j)
		{
			mark[i*prime[j]]=false;
			if(i%prime[j]==0)  break;
		}
	}
	mark[6]=true;
	for(i=4;i<=M;i<<=1)
	  mark[i]=true;
}
void build(int k,int l,int r)
{
	if(l==r)
	{
		sum[k]=mark[a[l]];
		maxn[k]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	sum[k]=sum[k<<1]+sum[k<<1|1];
	maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);
}
int query(int k,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)  return sum[k];
	int s=0,mid=(l+r)>>1;
	if(x<=mid)  s+=query(k<<1,l,mid,x,y);
	if(y>mid)  s+=query(k<<1|1,mid+1,r,x,y);
	return s;
}
void mod(int k,int l,int r,int x,int y,int s)
{
	if(maxn[k]<s)  return;
	if(l==r)
	{
		maxn[k]%=s;
		sum[k]=mark[maxn[k]];
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)  mod(k<<1,l,mid,x,y,s);
	if(y>mid)  mod(k<<1|1,mid+1,r,x,y,s);
	sum[k]=sum[k<<1]+sum[k<<1|1];
	maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);
}
void change(int k,int l,int r,int x,int y)
{
	if(l==r)
	{
		sum[k]=mark[y];
		maxn[k]=y;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)  change(k<<1,l,mid,x,y);
	else  change(k<<1|1,mid+1,r,x,y);
	sum[k]=sum[k<<1]+sum[k<<1|1];
	maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);
}
int main()
{
//	freopen("good.in","r",stdin);
//	freopen("good.out","w",stdout);
	int x,y,i,p,s;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	  scanf("%d",&a[i]);
	init();
	build(1,1,n);
	for(i=1;i<=m;++i)
	{
		scanf("%d",&p);
		if(p==1)
		{
			scanf("%d%d",&x,&y);
			printf("%d\n",query(1,1,n,x,y));
		}
		if(p==2)
		{
			scanf("%d%d%d",&x,&y,&s);
			mod(1,1,n,x,y,s);
		}
		if(p==3)
		{
			scanf("%d%d",&x,&y);
			change(1,1,n,x,y);
		}
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81014341
今日推荐