此题求期望的方式比较套路,所以求出期望,再乘上 n ! n! n!即可。
每个点被计算的期望次数是 ∑ j = 1 n P ( i , j ) \sum\limits_{j=1}^n P(i,j) j=1∑nP(i,j), P ( i , j ) P(i,j) P(i,j)表示删去 j j j时 i i i还与 j j j连通的概率——相当于 j j j是区间 [ i , j ] [i,j] [i,j]第一个删去的数的概率,即 1 j − i + 1 \dfrac{1}{j-i+1} j−i+11
每个 A i , B i A_i,B_i Ai,Bi都只能选一次。
贪心的想,将所有 A i , B i A_i,B_i Ai,Bi一起升序排序,取前 n n n个就是最优答案,判断合法性的方法:
所以不合法的情况只有:每个点只被取了 A i , B i A_i,B_i Ai,Bi中的一个,且不是全部取的同一边。
特殊判断一下全选 A , B A,B A,B是否合法,以及枚举 i ∈ [ 1 , n ] i\in[1,n] i∈[1,n],强制 A i , B i A_i, B_i Ai,Bi都选时,贪心选出的最小代价,取 min \min min即可。
不好考虑每种方案的代价,转而考虑每个左端点为 l l l,右端点为 r r r的连通块对答案的贡献。
区间 D P DP DP,预处理 c n t i cnt_i cnti表示 2 i 2i 2i个点任意组成 i i i个点对的方案数。
设 f [ l ] [ r ] f[l][r] f[l][r]表示只在区间 [ l , r ] [l,r] [l,r]内部互相连, l , r l,r l,r相互连通的方案数, a n s = f [ l ] [ r ] × c n t [ 外 部 点 个 数 ] ans=f[l][r]\times cnt[外部点个数] ans=f[l][r]×cnt[外部点个数](注意有些点对在前 K K K次操作中已经固定,需要判定是否兼容)
容斥求出 f [ l ] [ r ] f[l][r] f[l][r],设 g [ l ] [ r ] g[l][r] g[l][r]表示只在区间 [ l , r ] [l,r] [l,r]内部互相连的方案数( c n t [ 内 部 点 个 数 ] cnt[内部点个数] cnt[内部点个数]):
f [ l ] [ r ] = c n t [ 内 部 点 个 数 ] − ∑ i = l r − 1 f [ l ] [ i ] ⋅ g [ i + 1 ] [ r ] f[l][r]=cnt[内部点个数]-\sum\limits_{i=l}^{r-1}f[l][i]·g[i+1][r] f[l][r]=cnt[内部点个数]−i=l∑r−1f[l][i]⋅g[i+1][r]
贪心按位确定,设确定前缀中, 0 0 0的最后一个位置为 m a x 0 max_0 max0,前缀最大值个数为 c n t 0 cnt_0 cnt0, 1 1 1的最后一个位置为 m a x 1 max_1 max1,前缀最大值个数为 c n t 1 cnt_1 cnt1,设剩下部分 0 0 0最大值位置依次为 a 1 , a 2 , . . , a x a_1,a_2,..,a_x a1,a2,..,ax, 1 1 1最大值位置依次为 b 1 , b 2 , . . , b y b_1,b_2,..,b_y b1,b2,..,by,原序列后缀最大值依次为 c 1 , c 2 , . . . , c z c_1,c_2,...,c_z c1,c2,...,cz,存在以下性质:
显然这些条件是充要的(非后缀最大值可以放在最大值位置后面),那么问题转成了判断是否存在合法解:
强制 a ⊆ c a\subseteq c a⊆c—— b b b选了一些 ∉ c \notin c ∈/c和 ∈ c \in c ∈c的位置, c c c中剩下的位置序列就是 a a a。
如果合法,这样一定能构造出一组可行解:
首先显然不存在 a a a选完 c c c还选了其它位置的情况。
其次 a , b a,b a,b都选了一些 ∈ c \in c ∈c和 ∉ c \notin c ∈/c的情况都可以转化为上面的强制的情况——把 a a a中 ∉ c \notin c ∈/c的位置改成 1 1 1(显然这样不会影响 b b b),然后 b b b再通过调整 ∉ c \notin c ∈/c的位置使得 y = x y=x y=x。
假设 c c c中 k k k个数 ∈ b \in b ∈b,非 c c c位置中 m m m个数 ∈ b \in b ∈b,则 c n t 0 + z − k = c n t 1 + k + m cnt_0+z-k=cnt_1+k+m cnt0+z−k=cnt1+k+m,即:
c n t 0 − c n t 1 + = z = 2 k + m cnt_0-cnt_1+=z=2k+m cnt0−cnt1+=z=2k+m
等式左侧都是常数,相当于 ∈ c \in c ∈c的位置权值为 2 2 2, ∉ c \notin c ∈/c的位置权值为 1 1 1,需要在后缀中找出一个上升序列权值等于某个数。
显然 c c c能凑出, c − 2 c-2 c−2也能凑出,分别维护上升序列表示出的最大奇偶总值即可。
#include
using namespace std;
const int N=2e5+10,M=6e6+10;
int n,a[N],val[N],suf[N];
int pos[N][2],mx[2],mn[2][2],le[2][2];
char ans[N];
struct BIT{
int t[N],tg[M],vl[M],cnt;
inline void ad(int x,int vv)
{
for(;x<=n;x+=(x&(-x))){
tg[++cnt]=x;vl[cnt]=t[x];
t[x]=max(t[x],vv);
}
}
inline int get(int x)
{
int re=-1e9;
for(x=min(x,n);x;x-=(x&(-x))) re=max(re,t[x]);
return re;
}
inline void reback(int x){for(;cnt>x;t[tg[cnt]]=vl[cnt--]);}
}bit[2];
int main(){
scanf("%d",&n);
int i,j,k,x,y,cur=n+1,ptr,nq=0;
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
a[i]=n+1-a[i];
if(cur>a[i]){
cur=a[i];val[i]=2;
}else val[i]=1;
}
memset(bit[1].t,0x8f,sizeof(bit[1].t));
for(i=n;i;--i) suf[i]=suf[i+1]+(val[i]==2);
for(i=n;i>1;--i){
for(j=0;j<2;++j) mx[j]=max(0,bit[j].get(a[i]));
for(j=0;j<2;++j){
x=mx[j]+val[i];
bit[x&1].ad(a[i],x);
}
for(j=0;j<2;++j) pos[i][j]=bit[j].cnt;
}
mn[0][0]=mn[0][1]=n+1;
for(i=1;i<=n;++i){
nq^=1;
if(i<n) for(j=0;j<2;++j) bit[j].reback(pos[i+1][j]);
for(j=0;j<2;++j){
for(k=0;k<2;++k) mn[nq][k]=mn[nq^1][k],le[nq][k]=le[nq^1][k];
if(a[i]<mn[nq^1][j]){mn[nq][j]=a[i];le[nq][j]=le[nq^1][j]+1;}
ptr= i==n?(le[nq][0]==le[nq][1]):0;
if(i<n){
for(k=0;k<2;++k){
x=le[nq][k]-le[nq][k^1]+suf[i+1];
if(x>=0 && x<=bit[x&1].get(mn[nq][k^1])){ptr=1;break;}
}
}
if(ptr){ans[i]='0'+j;break;}
}
if(!ans[i]){printf("-1");return 0;}
}
for(i=1;i<=n;++i) putchar(ans[i]);
return 0;
}
太难了咕咕咕