【Atcoder】AGC028 B-E简要题解

*B.Removing Blocks

此题求期望的方式比较套路,所以求出期望,再乘上 n ! n! n!即可。

每个点被计算的期望次数是 ∑ j = 1 n P ( i , j ) \sum\limits_{j=1}^n P(i,j) j=1nP(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} ji+11


C.Min Cost Cycle

每个 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 i A_i Ai,要么都取的 B i B_i Bi
  • 否则必然存在一些点 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即可。


*D.Chords

不好考虑每种方案的代价,转而考虑每个左端点为 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=lr1f[l][i]g[i+1][r]


*E.High Elements

贪心按位确定,设确定前缀中, 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,存在以下性质:

  • m a x 0 < a 1 < . . . < a x max_0<a_1<...<a_x max0<a1<...<ax
  • m a x 1 < b 1 < . . . < b y max_1<b_1<...<b_y max1<b1<...<by
  • c n t 0 + x = c n t 1 + y cnt_0+x=cnt_1+y cnt0+x=cnt1+y
  • c i ( 1 ≤ i ≤ z ) c_i(1\leq i\leq z) ci(1iz)要么 ∈ a \in a a,要么 ∈ b \in b b

显然这些条件是充要的(非后缀最大值可以放在最大值位置后面),那么问题转成了判断是否存在合法解:
强制 a ⊆ c a\subseteq c ac—— 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+zk=cnt1+k+m,即:
c n t 0 − c n t 1 + = z = 2 k + m cnt_0-cnt_1+=z=2k+m cnt0cnt1+=z=2k+m

等式左侧都是常数,相当于 ∈ c \in c c的位置权值为 2 2 2 ∉ c \notin c /c的位置权值为 1 1 1,需要在后缀中找出一个上升序列权值等于某个数。

显然 c c c能凑出, c − 2 c-2 c2也能凑出,分别维护上升序列表示出的最大奇偶总值即可。

#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;
}


F.Reachable Cells

太难了咕咕咕

你可能感兴趣的:(妙,树状数组,贪心,atcoder)