把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5355 [Ynoi2017]由乃的玉米田

题面传送门

Ynoi虐我千百遍,我待sjjg如初见

话说\(Ynoi\)真是毒瘤,不开寄存器居然过不去。
这道题前三问可以从小清新人渣的本愿过来,开个\(bitset\)暴力乱搞就好了。
主要是第四问。
考虑暴力乱搞(这还要考虑?),那么\(x=1\)的时候复杂度将会很高,达到了\(\frac{n}{w}\)
考虑优化。
采用数据分治,将第四种运算中的\(x\leq s\)的点拿出来单独算。
我们可以对每一个拿出来的\(x\)暴力莫队,在过程中统计个数,最后确定个数。设拿出来\(y\)个,时间复杂度\(O((sn+y)\sqrt n)\),所以\(s\)不便过大。
那么\(s\)取多少呢?
如果满足数据随机分布,我们要让\(y\sqrt n < \frac{n}{w}\),则在当前\(10^5\)的数据下,\(y\leq 9\),经手动二分 精确计算\(y\)取值在\(5\)最好。那么\(s\)的取值也基本为这个数。
那你是不是以为这样就过了呢?
不,你得卡常!
代码实现:

#include<cstdio>
#include<algorithm>
#include<bitset>
#include<cmath>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,a[100039],ans[100039],s[100039],tot,now,head,pus,tmp,tots;
struct yyy{
	int x,y,z,now,num;
}f[100039],g[100039];
inline bool cmp(yyy x,yyy y){
	return (x.x/k==y.x/k)?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x;
}
inline bool cmp1(yyy x,yyy y){
	if(x.z!=y.z) return x.z<y.z;
	return (x.x/k==y.x/k)?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x;
}
inline void read(int &x){
	char s=getchar();x=0;
	while(s<'0'||s>'9') s=getchar();
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
bitset<100039> s1,s2;
int main(){
	//freopen("1.in","r",stdin);
	register int i,l=1,r=0,j,h;
	register yyy tmps;
	scanf("%d%d",&n,&m);
	k=sqrt(n);
	for(i=1;i<=n;i++) read(a[i]),tot=max(tot,a[i]);
	//pus=sqrt(tot);
	for(i=1;i<=m;i++){
		read(now);read(x);read(y);read(z);
		if(now==4&&z<5&&z!=0)g[++tmp]=(yyy){x,y,z,now,i};
		else f[++head]=(yyy){x,y,z,now,i};
	}
	sort(f+1,f+head+1,cmp);
	for(i=1;i<=head;i++){
		tmps=f[i];
		while(l<tmps.x){
			s[a[l]]--;
			if(!s[a[l]])s1[a[l]]=0,s2[tot-a[l]]=0;
			l++;
		}
		while(r>tmps.y){
			s[a[r]]--;
			if(!s[a[r]])s1[a[r]]=0,s2[tot-a[r]]=0;
			r--;
		}
		while(l>tmps.x){
			l--;
			s[a[l]]++;
			if(s[a[l]]==1)s1[a[l]]=1,s2[tot-a[l]]=1;
		}
		while(r<tmps.y){
			r++;
			s[a[r]]++;
			if(s[a[r]]==1)s1[a[r]]=1,s2[tot-a[r]]=1;
		}
		if(tmps.now==1)ans[tmps.num]=(s1&(s1<<tmps.z)).any();
		if(tmps.now==2)ans[tmps.num]=(s1&(s2>>(tot-tmps.z))).any();
		if(tmps.now==3){
			for(j=1;j*j<=tmps.z;j++) if(tmps.z%j==0&&(s1[j]&s1[tmps.z/j])) {ans[tmps.num]=1;break;}
		}
		if(tmps.now==4){
			if(tmps.z==0) ans[tmps.num]=((s1.count()-s1[0]>=1)&&s1[0]);
			else for(j=1;j*tmps.z<=tot;j++) if(s1[j]&s1[j*tmps.z]){ans[tmps.num]=1;break;}
		}
	}
	sort(g+1,g+tmp+1,cmp1);
	for(i=1;i<=tmp;i++){
		for(j=i;j<=tmp;j++) if(g[j].z!=g[j+1].z) break;
		l=1;r=0;tots=0;
		memset(s,0,sizeof(s));
		for(h=i;h<=j;h++){
			tmps=g[h];
			while(r<tmps.y){
				r++;
				s[a[r]]++;
				if(a[r]*tmps.z<=tot)tots+=s[a[r]*tmps.z];
				if(a[r]%tmps.z==0) tots+=s[a[r]/tmps.z];
			}
			while(l>tmps.x){
				l--;
				s[a[l]]++;
				if(a[l]*tmps.z<=tot)tots+=s[a[l]*tmps.z]; 
				if(a[l]%tmps.z==0)tots+=s[a[l]/tmps.z]; 
			}
			while(r>tmps.y){
			    if(a[r]*tmps.z<=tot) tots-=s[a[r]*tmps.z];
			    if(a[r]%tmps.z==0) tots-=s[a[r]/tmps.z];
				s[a[r]]--;
				r--;
			}
			while(l<tmps.x){
			    if(a[l]*tmps.z<=tot) tots-=s[a[l]*tmps.z];
			    if(a[l]%tmps.z==0)tots-=s[a[l]/tmps.z]; 
				s[a[l]]--;
				l++;
			}
			//printf("%d %d %d %d\n",l,r,g[h].z,tots);
			if(tots) ans[tmps.num]=1;
		}
		i=j;
	}
	for(i=1;i<=m;i++){
		if(ans[i]) printf("yuno\n");
		else printf("yumi\n");
	}
}

\(111\)行,\(2846\)字节。已经算是\(Ynoi\)中代码量很少的一部分题了。

posted @ 2020-04-17 16:19  275307894a  阅读(81)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end