【CF392D】Three Arrays-set+multiset
测试地址:Three Arrays
题目大意:有三个长为的数列,要求从中取前个数,从中取前个数,从中取前个数,使得取出的数的并集和这三个数列的并集相等,求最小的。
做法:本题需要用到set+multiset。
这题也是清北学堂讲的,思想非常不错,写在这里跟大家分享。
考虑只有两个数列怎么做,先预处理出,表示在或中最早出现的位置。我们可以从大到小枚举,越小,对的限制越多,每个限制都形如这种形式,这样我们可以求出。
那么现在有三个数列,我们又要怎么做呢?也是考虑从大到小枚举,越小,对的限制越多,每个限制都形如:或。以为横纵坐标建平面直角坐标系,将限制映射到坐标系上,我们发现这其实就是将点左下的区域全部挖去。那么此时我们怎么找最小的呢?观察发现,我们挖掉不能取的那些区域后,剩下的区域有很多向左下凸出来的拐角,那么最小的必定在这些拐角中的一个取得。所以我们现在的目标就是维护这个阶梯形状的东西。
考虑维护组成阶梯形的那些限制。随着的变小,对的限制不断增多,也就是不断挖掉新的区域,有时我们会发现新的区域包含了一些旧的区域,这时候旧的区域就没有必要存下来了,我们就删除这个限制。又因为一个区域最多加入一次、删除一次,一共有不超过个区域,用set维护的话,就可以做到的复杂度了。同时再用一个multiset来维护拐角上的所有可能取值即可。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,a[100010],b[100010],c[100010],tot;
int fa[300010]={0},fb[300010]={0},fc[300010]={0};
struct forsort
{
int val,id1,id2;
}f[300010];
struct Pair
{
int b,c;
};
bool operator < (Pair a,Pair b) {return a.b<b.b;}
set<Pair> s;
set<Pair>::iterator it;
multiset<int> vals;
multiset<int>::iterator valit;
bool cmp(forsort a,forsort b)
{
return a.val<b.val;
}
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[++tot].val);
f[tot].id1=1,f[tot].id2=i;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&f[++tot].val);
f[tot].id1=2,f[tot].id2=i;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&f[++tot].val);
f[tot].id1=3,f[tot].id2=i;
}
sort(f+1,f+3*n+1,cmp);
tot=0;
for(int i=1;i<=3*n;i++)
{
if (i==1||f[i].val!=f[i-1].val) tot++;
if (f[i].id1==1) a[f[i].id2]=tot;
if (f[i].id1==2) b[f[i].id2]=tot;
if (f[i].id1==3) c[f[i].id2]=tot;
}
for(int i=1;i<=n;i++)
if (!fa[a[i]]) fa[a[i]]=i;
for(int i=1;i<=n;i++)
if (!fb[b[i]]) fb[b[i]]=i;
for(int i=1;i<=n;i++)
if (!fc[c[i]]) fc[c[i]]=i;
}
void insertPair(int newb,int newc)
{
int nowb,nowc;
Pair e={newb,newc};
it=s.upper_bound(e);
if ((*it).c>=e.c) return;
nowc=(*it).c;
it--;
valit=vals.find((*it).b+nowc);
vals.erase(valit);
while((*it).c<=e.c)
{
nowb=(*it).b,nowc=(*it).c;
it--;
vals.erase((*it).b+nowc);
it++;
s.erase(it);
it=s.lower_bound(e);
it--;
}
nowb=(*it).b,nowc=(*it).c;
vals.insert(nowb+e.c);
it++;
nowc=(*it).c;
vals.insert(e.b+nowc);
s.insert(e);
}
void work()
{
Pair e;
e.b=0,e.c=inf+1;
s.insert(e);
e.b=inf+1,e.c=0;
s.insert(e);
vals.insert(0);
for(int i=1;i<=tot;i++)
if (!fa[i]) insertPair(fb[i]?fb[i]:inf,fc[i]?fc[i]:inf);
int ans=inf;
bool flag=1;
for(int i=n;i>=1;i--)
{
ans=min(ans,i+(*vals.begin()));
if (fa[a[i]]==i)
{
if (!fb[a[i]]&&!fc[a[i]]) {flag=0;break;}
insertPair(fb[a[i]]?fb[a[i]]:inf,fc[a[i]]?fc[a[i]]:inf);
}
}
if (flag) ans=min(ans,(*vals.begin()));
printf("%d",ans);
}
int main()
{
init();
work();
return 0;
}