题解 CF914D【Bash and a Tough Math Puzzle】

这篇博客详细介绍了如何使用分块技术解决竞赛编程题目CF914D。文章首先对比了该题与P4145题的相似之处,然后针对修改和查询操作进行了分类讨论,提出在修改操作中直接更新区间lazy标记,并在查询操作中判断区间内不能被x整除的数的个数。此外,还讨论了优化策略,包括使用快读、优化循环变量和提前结束查询等,以应对大数据量的挑战。最后给出了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分块

看到没有写分块的,那我就写一篇分块的题解

这道题很像P4145,都是暴力修改+优化

对于修改操作和查询操作分类讨论:

  1. 修改

    修改很简单,直接单点修改并更新区间lazy标记(区间gcd值)

  2. 查询

    显然,对于区间内不能被x整除的数的个数大于1时显然怎么改也不能符合要求。

    所以我们只要查询区间内不能被x整除的数的个数就好了

    那么如何把区间gcd值改为不能被x整除的数呢?

    我们容易知道,如果区间gcd值 m o d x = 0 mod x=0 modx=0,那么这个区间里的数肯定都能被x整除

    如果不等于0,就暴力遍历即可

优化

  1. 数据量比较大,使用快读
  2. 将频繁使用的循环变量改为register
  3. 查询时如果区间内不能被x整除的数的个数已经 > 2 >2 >2,就直接输出NO并return

这样就可以用分块通过本题啦

代码

#include<bits/stdc++.h>
using namespace std;
namespace FAST_IO
{
	template<typename T> void read(T &a)
	{
		a=0;
		int f=1;
		char c=getchar();
		while(!isdigit(c))
		{
			if(c=='-')
			{
				f=-1;
			}
			c=getchar();
		}
		while(isdigit(c))
		{
			a=a*10+c-'0';
			c=getchar();
		}
		a=a*f;
	}
	template <typename T> void write(T a)
	{
		if(a<0)
		{
			a=-a;
			putchar('-');
		}
		if(a>9)
		{
			write(a/10);
		}
		putchar(a%10+'0');
	}
	template <typename T> void writeln(T a)
	{
		write(a);
		puts("");
	}
}//快读
const int maxn=5e5+999;
int belong[maxn],l[maxn],r[maxn],num,_size;
int n,a[maxn],add[maxn],lazy[maxn];
void build()
{
	_size=sqrt(n);
	num=n/_size;
	if(n%_size)
	{
		num++;
	}
	for(int i=1;i<=num;i++)
	{
		l[i]=(i-1)*_size+1;
		r[i]=i*_size;
	}
	r[num]=n;
	for(int i=1;i<=n;i++)
	{
		FAST_IO::read(a[i]);
		belong[i]=i/_size;
		if(i%_size)
		{
			belong[i]++;
		}
		lazy[belong[i]]=__gcd(lazy[belong[i]],a[i]);
	}
} 
void update(int pos,int c)
{
	int x=belong[pos];
	a[pos]=c;
	lazy[x]=0;
	for(register int i=l[x];i<=r[x];i++)
	{
		lazy[x]=__gcd(lazy[x],a[i]);
	}
}
void ask1(int ls,int rs ,int xt)
{
	int ans=0;
	int x=belong[ls],y=belong[rs];
	register int i,j;
	if(x==y)
	{
		for(i=ls;i<=rs;i++)
		{
			if(a[i]%xt!=0)
			{
				ans++;
			}
		}
	}
	else
	{
		for(i=ls;i<=r[x];i++)
		{
			if(a[i]%xt!=0)
			{
				ans++;
			}
		}			
		if(ans>=2)
		{
			puts("NO");
			return;
		}
		for(i=x+1;i<=y-1;i++)
		{
			if(lazy[i]%xt!=0)
			{
				for(j=l[i];j<=r[i];j++)
				{
					if(a[j]%xt!=0)
					{
						ans++;
					}
				}			
				if(ans>=2)
				{
					puts("NO");
					return;
				}	
			}
		}
		for(i=l[y];i<=rs;i++)
		{
			if(a[i]%xt!=0)
			{
				ans++;				
			}
		}
	}
	if(ans>=2)
	{
		puts("NO");
	}
	else
	{
		puts("YES");
	}
}
int op,ltt,rtt,x;
signed main()
{
	int f;
	FAST_IO::read(n);
	build();
	FAST_IO::read(f);
	while(f--)
	{
		FAST_IO::read(op);
		FAST_IO::read(ltt);
		FAST_IO::read(rtt);
		if(op==1)
		{
			FAST_IO::read(x);
			ask1(ltt,rtt,x);
		}
		else
		{
			update(ltt,rtt);
		}	
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值