Luogu P8986 [北大集训 2021] 基因编辑 题解
我们考虑这道题目要求我们在数列 \(s\) 中找到一个一个区间 \([i,j]\) 满足:
- \(l\in[1,l-1],r\in [r+1,n]\)
- \(j-i+1\) 最小化
- 在数列 \(s\) 中找不到一个与区间 \([i,j]\) 不同的区间 \([p,q]\) (即 \(i\ne p,j\ne q\) )满足 \(s_i=s_p,s_j=s_q\)
- \(s_i\ne s_j\)
我们不难发现后面两个条件可以转化为区间 \([i,j]\) 满足:
- \(\forall p\in [i,j-1]\cup [j+1,n] ,s_j\ne s_p\)
- \(\forall q\in [1,i-1]\cup [i+1,j] ,s_i\ne s_q\)
我们不妨在遍历 \(j\) 的同时用一个 set 来维护所有的 \(s_i\) ,满足 \(s_i\) 在 \(s_1\) 到 \(s_j\) 中仅出一次,再用桶维护从最接近 \(l\) 并且满足上述条件的 \(i\) 开始一直到 \(n\),数列 \(s\) 里每个数出现的次数,如果当前的 \(s_j\) 出现次数为1,那么这就最佳答案,直接输出,如果遍历完所有 \(j\) 但没有一个 \(j\) 满足上述条件,则不存在一个合法方案,输出 -1。
CODE
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
int n,l,r,s[1000005],book[1000005],id[1000005],cnt[1000005];
set<pair<int,int> > q;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>l>>r;
for(int i=1;i<=n;i++)
cin>>s[i];
for(int i=1;i<l;i++){
book[s[i]]++;
if(book[s[i]]==1){
id[s[i]]=i;
q.insert({l-i,s[i]});
}
else if(book[s[i]]==2){
auto it=q.find({l-id[s[i]],s[i]});
q.erase(it);
}
}
for(int i=l;i<=r;i++){
book[s[i]]++;
if(book[s[i]]==2&&id[s[i]]){
auto it=q.find({l-id[s[i]],s[i]});
q.erase(it);
}
}
auto it=q.begin();
pair<int,int> ttt=*it;
for(int i=n;i>=l-ttt.fi;i--)
cnt[s[i]]++;
for(int i=r+1;i<=n;i++){
book[s[i]]++;
if(book[s[i]]==2&&id[s[i]]){
auto it=q.find({l-id[s[i]],s[i]});
pair<int,int> ttt=*it;
q.erase(it);
auto iti=q.begin();
pair<int,int> kkk=*iti;
for(int j=l-kkk.fi;j<l-ttt.fi;j++)
cnt[s[j]]++;
}
if(cnt[s[i]]==1){
auto it=q.begin();
if(it==q.end())
continue;
pair<int,int> ttt=*it;
cout<<(i-l+ttt.fi+1);
return 0;
}
}
cout<<-1;
return 0;
}

浙公网安备 33010602011771号