【题解】洛谷P3514、P6859 :LIZ-Lollipop、蝴蝶与花

P3514 [POI2011] LIZ-Lollipop

很好的思维题,也是一个结论题,只有1、2的性质很重要,结论:当存在 \(k(k>2)\),必然可以得到 \(k-2\)

得到 \(k\) 的区间 \(l_k\)\(r_k\) 必然会有 \(a_{l_k}=2\)\(a_{r_k}=2\)\(a_{l_k}=a_{r_k}=1\),这样无论如何都能减去一段或两端得到 \(k-2\)

这样如果一个数存在,那比他小的所有奇偶性相同的数就都存在,我们就可以求出最大的奇数偶数来判断是否合法。

求答案区间,我们可以在求最大奇偶数时记录存在该数的区间,然后通过逆推式求出每个存在的数的区间。

#include <bits/stdc++.h>
#define int long long
#define re register 
const int N=2e6+10;
using namespace std;

int n,m,a[N],sum[N],mx[4];
int l[N];
int r[N];

void up(int k,int x,int y){
	if(k>mx[k%2]){
		mx[k%2]=k;
		l[k]=x;
		r[k]=y;
	}
}

void down(int &l,int &r,int pl,int pr){
	if(pl==0&&pr==0){
		return;
	}
	l=pl;
	r=pr;
	if(a[pl]==2){
		l++;
	}
	else if(a[pr]==2){
		r--;
	}
	else{
		l++;
		r--;
	}
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
	
	cin>>n>>m;
	
	for(int i=1;i<=n;i++){
		char c;
		cin>>c;
		a[i]=(c=='T')?2:1;
		sum[i]=sum[i-1]+a[i];
	}
	
	for(int i=1;i<=n;i++){
		up(sum[i]-sum[0],1,i);
		up(sum[n]-sum[i],i+1,n);
	}
	up(sum[n]-sum[0],1,n);
	
	for(int i=2*n;i>=1;i--){
		down(l[i],r[i],l[i+2],r[i+2]);
	}
	
	for(int i=1;i<=m;i++){
		int k;
		cin>>k;
		if(k>mx[k%2]){
			cout<<"NIE\n";
			continue;
		}
		cout<<l[k]<<" "<<r[k]<<"\n";
	}
	return 0;
}

P6859 蝴蝶与花

讲的有点烂,看看大佬写法

这次加上了修改操作怎么办呢,没事用树状数组维护前缀和即可,但是时间还是不太够,我们通过发现问题本质。

我们想二分查找该怎么做,枚举左端点二分查找右端点,当 \([l,r_1]\) 区间和 \(k\) 为只能为 \(s\)\(s+1\),如果 \(k\) 大于 \(s+1\) 时,\(r\) 右移一格一定不小于 \(s\)

如果 \([l+1,r_2]\) 的区间和也是 \(s+1\) 的话那必然 \(a_l\)\(a_{r_1}\) 为 2,这个可以反证法,继续向下类举下去如果两个端点一直是 \(2\) 的话区间和就不会变。

所以我们 \(1\) 作为左端点二分右端点 \(pos\),统计点 \(1\) 后的 \(2\) 的数量和 \(pos\) 后的 \(2\) 的数量,向后平移即可。

树状数组 \(O(n\log^2 n)\)

#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1 
#define re register 
#define ll long long
#define lb(x) x&-x
const int N=4e6+100;
const int mod=998244353;
using namespace std;

int n,m;
int a[N];
int sum[N*2];

void addsum(int x,int k){
	while(x<=n){
		sum[x]+=k;
		x+=lb(x);
	}
}

int querysum(int x){
	int ans=0;
	while(x){
		ans+=sum[x];
		x-=lb(x);
	}
	return ans;
}

signed main(){
//	freopen("kingdom3.in","r",stdin);
//	freopen("a.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
	
	cin>>n>>m;
	
	for(re int i=1;i<=n;i++){
		cin>>a[i];
		addsum(i,a[i]);
	}
	
	while(m--){
		int x,y;
		char c;
		cin>>c;
		if(c=='A'){
			cin>>x;
			
			if(x==0){
				cout<<"none\n";
				continue;
			}
			
			int l=1,r=n,mid,pos;
			while(l<=r){
				mid=(l+r)>>1;
				if(querysum(mid)>=x){
					pos=mid;
					r=mid-1;
				}
				else{
					l=mid+1;
				}
			}
			
			int z=querysum(pos);
			if(z<x){
				cout<<"none\n";
				continue;
			}
			if(z==x){
				cout<<1<<" "<<pos<<"\n";
				continue;
			}
			int len1=0,len2=0;
			
			l=1,r=n;
			while(l<=r){
				mid=(l+r)>>1;
				if(querysum(mid)==mid*2){
					len1=mid;
					l=mid+1;
				}
				else{
					r=mid-1;
				}
			}
			
			l=1,r=n;
			while(l<=r){
				mid=(l+r)>>1;
				if(querysum(pos+mid-1)-querysum(pos-1)==mid*2){
					len2=mid;
					l=mid+1;
				}
				else{
					r=mid-1;
				}
			}
			
			if(len1<len2){
				if(querysum(pos+len1)-querysum(2+len1-1)!=x){
					cout<<"none\n";
					continue;
				}
				cout<<2+len1<<" "<<pos+len1;
			}
			else{
				if(querysum(pos+len2)-querysum(len2)!=x){
					cout<<"none\n";
					continue;
				}
				cout<<1+len2<<" "<<pos+len2;
			}
			cout<<"\n";
		}
		else{
			cin>>x>>y;
			addsum(x,-a[x]);
			addsum(x,y);
			a[x]=y;
		}
	}
	return 0;
}
posted @ 2024-11-13 09:29  sad_lin  阅读(2)  评论(0编辑  收藏  举报