【题解】洛谷P3674、P5355: 小清新人渣的本愿和 [Ynoi2017] 由乃的玉米田

P3674 小清新人渣的本愿

自己想出来了,好耶!!其实和兔子洞那题差不多,标记哪些数区间中出现了,因为 bitset 就相当于状压,也是支持位运算的,所以减法相当于右移 \(x\) 位后与运算,如果有交说明可以得到 \(x\),加法就要额外维护 \(g=f_{N-i}\),查询时直接查找 \(f\)\(g\) 右移 \(N-x\) 位是否有交,乘法更简单直接分解因数就可以,这样的复杂度位 \(O(m(\sqrt{n}+\frac{n}{w}))\)

\(a+b=x,b=x-a\),所以维护加要进行减操作。

其实不随机的话可以是 \(O(\frac{n^2}{w}\sqrt{n})\),这样是乘法拉满的情况,但是数据范围没这么出就不管了。

#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
#define pir pair<int,int>
const int N=1e5+10,M=25005;
const int mod=1e8;
using namespace std;

int n,m;
int a[N];
int of[N],len;
bitset<N> f,g;
int cnt[N];

struct ss{
	int l,r,op,id,x;
}q[N];

void add(int x){
	cnt[a[x]]++;
	if(cnt[a[x]]==1){
		f[a[x]]=1;
		g[N-a[x]]=1;
	}
}

void del(int x){
	if(cnt[a[x]]==1){
		f[a[x]]=0;
		g[N-a[x]]=0;
	}
	cnt[a[x]]--;
}

int ans[N];

bool cmp(ss g,ss h){
	return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:(of[g.l]&1)?of[g.r]<of[h.r]:of[g.r]>of[h.r];
}

signed main(){
//	freopen("xp1.in","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    
    cin>>n>>m;
	
	len=sqrt(n);
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
	} 
    
    for(int i=1;i<=m;i++){
    	int op,l,r,x;
    	cin>>op>>l>>r>>x;
    	q[i].id=i;q[i].l=l;q[i].r=r;q[i].op=op;q[i].x=x;
    	of[i]=(i-1)/len+1;
	}
    
    sort(q+1,q+m+1,cmp); 
    
    int l=1,r=0;
    
    for(int i=1;i<=m;i++){
    	int ql=q[i].l,qr=q[i].r,id=q[i].id,x=q[i].x,op=q[i].op;
		while(l>ql) add(--l); 
    	while(r<qr) add(++r);
    	while(l<ql) del(l++);
    	while(r>qr) del(r--);
    	
    	int flag=0;
    	
    	
    	
    	if(op==1){
    		if((f&(f>>x)).any()){
    			flag=1;
			}
		}
		else if(op==2){
			if((f&(g>>(N-x))).any()){
				flag=1;
			}
		}
		else{
			for(int j=1;j*j<=x;j++){
				if(x%j==0&&f[j]==1){
					if(f[x/j]==1){
						flag=1;
						break;
					}
				}
			}
		}
		
		ans[id]=flag;
	}
	
	for(int i=1;i<=m;i++){
		if(ans[i]){
			cout<<"hana";
		}
		else{
			cout<<"bi";
		}
		cout<<"\n";
	}
	return 0;
}

P5355 [Ynoi2017] 由乃的玉米田

然后就是升级版,增添了除法操作。

分类讨论,对于 \(x> \sqrt{N}\) 的部分通过枚举除数来判断是否有合法的被除数,复杂度 \(O(\sqrt{n})\)

对于 \(x\le \sqrt{N}\) 同一处理,p从1到n遍历序列,\(las_i\) 表示 \(i\) 数字上一次出现的最后的位置,\(mx_i\) 表示 \(i\) 位置满足在 \([l,p]\) 同时出现 \(y\)\(xy\),或同时存在 \(y\)\(\frac{y}{x}\) 靠右的位置,每扫到一个点都更新 \(mx\)

查询时判断当前 \(x\)\(mx_r\ge l\)

我们每次枚举复杂度为 \(O(n)\),一共有 \(\sqrt{n}\) 个数,所以处理这些数的总复杂度为 \(O(n\sqrt{n})\)

#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
#define pir pair<int,int>
const int N=1e5+10,M=25005;
const int mod=1e8;
using namespace std;

int n,m;
int a[N];
int of[N],len;
bitset<N> f,g;
int cnt[N];

struct ss{
	int l,r,op,id,x;
}q[N];

void add(int x){
	cnt[a[x]]++;
	if(cnt[a[x]]==1){
		f[a[x]]=1;
		g[N-a[x]]=1;
	}
}

void del(int x){
	if(cnt[a[x]]==1){
		f[a[x]]=0;
		g[N-a[x]]=0;
	}
	cnt[a[x]]--;
}

int ans[N];

bool cmp(ss g,ss h){
	return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:(of[g.l]&1)?of[g.r]<of[h.r]:of[g.r]>of[h.r];
}

struct sa{
	int l,r,id;
};

vector<sa> v[N];  
int las[N];
int res[N];
int mx[N];

void solve(){
	
	for(int i=1;i<=350;i++){
		if(v[i].empty()){
			continue;
		}
		memset(mx,0,sizeof mx);
		memset(las,0,sizeof las);
		int l=0;
		for(int j=1;j<=n;j++){
			las[a[j]]=j;
			if(i*a[j]<=N){
				l=max(l,las[i*a[j]]); 
			}
			if(a[j]%i==0){
				l=max(l,las[a[j]/i]);
			}
			mx[j]=l;
		}
		for(sa j:v[i]){
			ans[j.id]=(j.l<=mx[j.r]);
		}
		
	}
}

signed main(){
//	freopen("xp1.in","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    
    cin>>n>>m;
	
	len=sqrt(n);
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
		of[i]=(i-1)/len+1;
	} 
	
	int cntq=0;
    
    for(int i=1;i<=m;i++){
    	int op,l,r,x;
    	cin>>op>>l>>r>>x;
    	if(op==4&&x<=350){
    		v[x].push_back({l,r,i});
		}
		else{
			cntq++;
			q[cntq].id=i;q[cntq].l=l;q[cntq].r=r;q[cntq].op=op;q[cntq].x=x;
		}
	}
    
    sort(q+1,q+cntq+1,cmp); 
    
    int l=1,r=0;
    
    for(int i=1;i<=cntq;i++){
    	int ql=q[i].l,qr=q[i].r,id=q[i].id,x=q[i].x,op=q[i].op;
		while(l>ql) add(--l); 
    	while(r<qr) add(++r);
    	while(l<ql) del(l++);
    	while(r>qr) del(r--);
    	
    	int flag=0;
    	
    	if(op==1){
    		if((f&(f>>x)).any()){
    			flag=1;
			}
		}
		else if(op==2){
			if((f&(g>>(N-x))).any()){
				flag=1;
			}
		}
		else if(op==3){
			for(int j=1;j*j<=x;j++){
				if(x%j==0&&f[j]==1&&f[x/j]==1){
					flag=1;
					break;
				}
			}
		}
		else{
			for(int j=1;j*x<=N;j++){
				if(f[j]&&f[x*j]){
					flag=1;
					break;
				}
			}
		}
		ans[id]=flag;
	}
	
	solve();
	
	for(int i=1;i<=m;i++){
		if(ans[i]){
			cout<<"yuno";
		}
		else{
			cout<<"yumi";
		}
		cout<<"\n";
	}
	
	return 0;
}
posted @ 2024-11-26 15:28  sad_lin  阅读(47)  评论(0)    收藏  举报