【YNOI2017】【BZOJ4810】【洛谷P3674】由乃的玉米田 / 小清新人渣的本愿(莫队)(bitset)

BZOJ传送门

洛谷传送门


解析:

显然这种存在性问题可以考虑用bitset来解决。

对于乘法直接 O ( c ) O(\sqrt c) O(c )暴力枚举因数就行了。

对于减法,显然我们可以用bitset中的位移来操作一波。

对于加法,我们可以把它转换成减法,设所有 a a a值中的最大值为 c c c

则对于询问 b b b,如果有解 x + y = b x+y=b x+y=b,则 ( c − x ) − y = c − b (c-x)-y=c-b (cx)y=cb,于是我们维护一个反向的bitset,每次询问两个bitset里面有没有差为 c − b c-b cb的数就行了。


代码:

#include<bits/stdc++.h>
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=1e5+5;

int n,m,a[N];
std::bitset<N> t,B,R;
int bsiz;
int block[N];
struct Query{
	int l,r,id,typ,val;
	friend bool operator<(cs Query &a,cs Query &b){
		return block[a.l]==block[b.l] ? ((block[a.l]&1)?(a.r>b.r):(a.r<b.r)) : block[a.l]<block[b.l];
	}
}q[N];

int c,d,cnt[N];

inline void ins(int val){
	if(!(cnt[val]++)){
		B[val]=1;
		R[c-val]=1;
	}
}

inline void del(int val){
	if(!(--cnt[val])){
		B[val]=0;
		R[c-val]=0;
	}
}

inline bool check(int val,int typ){
	switch(typ){
		case 1:return (B&(B>>val)).count();
		case 2:return (B&(R>>(c-val))).count();
		case 3:{
			for(int re i=1;i*i<=val;++i)
			if(val%i==0&&B[i]&&B[val/i])return true;
			return false;
		}
	}
}

int l=1,r;
bool ans[N];
signed main(){
	n=getint(),m=getint();
	bsiz=std::max(1.,sqrt((double)n*n/m));
	for(int re i=1;i<=n;++i)c=std::max(c,a[i]=getint()),block[i]=i/bsiz;
	for(int re i=1;i<=m;++i){
		q[i].typ=getint();
		q[i].l=getint();
		q[i].r=getint();
		d=std::max(q[i].val=getint(),d);
		q[i].id=i;
	}
	c=std::max(c,d);
	std::sort(q+1,q+m+1);
	for(int re i=1;i<=m;++i){
		while(r<q[i].r)ins(a[++r]);
		while(l>q[i].l)ins(a[--l]);
		while(r>q[i].r)del(a[r--]);
		while(l<q[i].l)del(a[l++]);
		ans[q[i].id]=check(q[i].val,q[i].typ);
	}
	for(int re i=1;i<=m;++i)puts(ans[i]?"yuno":"yumi");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值