专栏文章
题解:P3587 [POI 2015 R2] 项链分割 Necklace partition
P3587题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min724l9
- 此快照首次捕获于
- 2025/12/01 21:37 3 个月前
- 此快照最后确认于
- 2025/12/01 21:37 3 个月前
观察题目,容易发现第一问就是求有多少区间 满足 且区间内的数的种类和区间外的数的种类没有交。
可以对右端点扫描线,考虑对于当前右端点 来说合法的左端点 需要满足什么要的条件:
- 如果 同时在 和 中出现,记 为 在 中最后一次出现的位置,则 需要不小于 , 可以在扫描线的同时用 set 维护。
- 如果 只出现在 中,则 要在 第一次出现的位置的左边,可以用线段树维护,求出有多少位置符合要求即可。
第二问容易发现只要求出长度大于 的区间中长度最小的和长度小于等于 中长度最大的即可,那么线段树二分就行。
时间复杂度 ,代码:
CPP#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,k,a[N],lst[N],pre[N],nxt[N],add[4*N],mn[4*N],cnt[4*N],ans2=1e9;
ll ans1;
set<int>s;
void push_down(int x){
if(add[x]){
add[2*x]+=add[x];
add[2*x+1]+=add[x];
mn[2*x]+=add[x];
mn[2*x+1]+=add[x];
add[x]=0;
}
}
void push_up(int x){
if(mn[2*x]<mn[2*x+1]) mn[x]=mn[2*x],cnt[x]=cnt[2*x];
else if(mn[2*x]>mn[2*x+1]) mn[x]=mn[2*x+1],cnt[x]=cnt[2*x+1];
else mn[x]=mn[2*x],cnt[x]=cnt[2*x]+cnt[2*x+1];
}
void build(int x,int l,int r){
cnt[x]=r-l+1;
if(l==r) return;
int mid=(l+r)/2;
build(2*x,l,mid);
build(2*x+1,mid+1,r);
}
void modify(int x,int l,int r,int L,int R,int v){
if(L>R) return;
if(l>=L&&r<=R){
add[x]+=v;
mn[x]+=v;
return;
}
push_down(x);
int mid=(l+r)/2;
if(L<=mid) modify(2*x,l,mid,L,R,v);
if(R>mid) modify(2*x+1,mid+1,r,L,R,v);
push_up(x);
}
pair<int,int>query(int x,int l,int r,int L,int R){
if(L>R) return make_pair(114514,0);
if(l>=L&&r<=R) return make_pair(mn[x],cnt[x]);
push_down(x);
int mid=(l+r)/2;
if(R<=mid) return query(2*x,l,mid,L,R);
if(L>mid) return query(2*x+1,mid+1,r,L,R);
pair<int,int>a=query(2*x,l,mid,L,R),b=query(2*x+1,mid+1,r,L,R);
if(a.first<b.first) return a;
if(a.first>b.first) return b;
return make_pair(a.first,a.second+b.second);
}
int queryl(int x,int l,int r,int h){
if(mn[x]) return l-1;
if(l==r){
if(!mn[x]) return l;
return l-1;
}
push_down(x);
int mid=(l+r)/2;
if(h<=mid) return queryl(2*x,l,mid,h);
int ans=queryl(2*x+1,mid+1,r,h);
if(ans>mid) return ans;
return queryl(2*x,l,mid,h);
}
int queryr(int x,int l,int r,int h){
if(mn[x]) return r+1;
if(l==r){
if(!mn[x]) return l;
return l+1;
}
push_down(x);
int mid=(l+r)/2;
if(h>mid) return queryr(2*x+1,mid+1,r,h);
int ans=queryr(2*x,l,mid,h);
if(ans<=mid) return ans;
return queryr(2*x+1,mid+1,r,h);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=lst[a[i]];
lst[a[i]]=i;
}
memset(lst,0,sizeof(lst));
for(int i=n;i>=1;i--){
nxt[i]=lst[a[i]];
lst[a[i]]=i;
}
build(1,1,n);
s.insert(0);
for(int i=1;i<n;i++){
if(pre[i]){
modify(1,1,n,pre[i]+1,i,1);
s.erase(pre[i]);
}
if(nxt[i]) s.insert(i);
auto it=s.upper_bound(i);
it--;
pair<int,int>p=query(1,1,n,(*it)+1,i);
if(!p.first){
ans1+=p.second;
int h=max(1,i-(n/2)+1),p1=0,p2=0;
if(h>1){
p1=queryl(1,1,n,h-1);
if(p1&&p1>=(*it)+1) ans2=min(ans2,2*(i-p1+1)-n);
}
p2=queryr(1,1,n,max(h,(*it)+1));
if(p2<=i) ans2=min(ans2,n-2*(i-p2+1));
}
}
cout<<ans1<<" "<<ans2<<'\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...