洛谷P3514 [POI2011] LIZ-Lollipop

前言

典中典思维蓝题难度薄纱模板水紫捏。

\(1\) \(2\) 序列这种也不是第一次见了,感觉多多少少都沾点 Ad-hoc。

话说这种考法真的好吗,一上来就是一个门槛很高的性质,推出来就满分,推不出来就 \(0\) 分,正推和反推的难度完全不是一个思维量级。

题意

Link

给一个只有 \(1\)\(2\) 的序列,每次询问有没有一个子串的和为 \(x\),序列长与询问次数均为 \(10^6\) 级。

思路

发挥惊人的观察力得到,假如一段区间的和为 \(sum\),则如果 \(sum>2\),那么这个区间一定有一个子区间的区间和为 \(sum-2\)。考虑两种情况,区间的左右端点有 \(2\) 和没有 \(2\),前者直接在原区间中减去 \(2\) 即可得到 \(sum-2\) 的子区间,后者说明区间左右端点都是 \(1\),那么原区间减去两个端点即可得到 \(sum-2\) 的子区间。

于是我们找到最大的奇数 \(sum\) 和偶数 \(sum\) 区间,再不断按照上述方法缩小两端点即可求出每个数对应的区间。

代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MAXN=1000005,MAXK=2000005;
int n,m,maxx[2]={0};
int a[MAXN],q=0,sum=0;
pii co[MAXK];
int main(){
    cin>>n>>m;
    string inp;
    cin>>inp;

    for(int i=1;i<=n;i++){
        a[i]=(inp[i-1]=='T'?2:1);
        sum+=a[i];
        maxx[sum%2]=max(maxx[sum%2],sum);
        co[sum].first=1;co[sum].second=i;
    }
    sum=0;
    for(int i=n;i>=1;i--){
        sum+=a[i];
        maxx[sum%2]=max(maxx[sum%2],sum);
        co[sum].first=i;co[sum].second=n;
    }
    for(int i=0;i<2;i++){
        int l=co[maxx[i]].first,r=co[maxx[i]].second,con=maxx[i];
        while(l<=r && con>0){
            co[con]=make_pair(l,r);
            if(a[l]==1 && a[r]==1) l++,r--;
            else if(a[l]==2) l++;
            else r--;
            con-=2;
        }
    }
    for(int i=1;i<=m;i++){
        cin>>q;
        if(q>maxx[q%2]) cout<<"NIE";
        else{
            cout<<co[q].first<<' '<<co[q].second;
        }
        if(i!=m) cout<<endl;
    }
    return 0;
}
posted @ 2024-10-31 09:34  MessageBoxA  阅读(2)  评论(0编辑  收藏  举报