【题解】洛谷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;
}