AtCoder Regular Contest 101

D - Median of Medians

老经典题了 /se

考虑二分答案,判断比它小的中位数个数。对于当前的 \(mid=x\) ,可以将原序列所有数看成 \(1\)\(-1\) ,统计就用 BIT,每次累加所有之前不大于它的前缀和即可(假设当前是 \(sum\) ,之前所有 \(<sum\) 的区间和它作差得到的也不小于 \(0\))。

bool Check( int x )
{
	memset( tr,0,sizeof(tr) );
	int sum=0; ll res=0,all=1ll*n*(n+1)/2;
	for ( int i=1; i<=n; i++ )
	{
		Add(ADD+sum,1);
		(a[i]>x) ? sum-- : sum++;
		res+=Query(ADD+sum-1);
	}
	return res>=all/2+1;
}

E - Ribbons on Tree

“覆盖所有路径” 很难处理,如果下放到所有子树,其实就是在匹配的时候不能有除根以外的子树 \(u\) 自匹配(这样就没有到 \(fa[u]\) 的边)。

\(dp[u][i]\) 表示子树 \(u\) 中还有 \(i\) 个没有匹配的合法方案数。易得 \(dp[u][i+j]=\sum dp[u][i]\times dp[v][j]\) ,注意 \(dp[u][0]\) 要去掉自匹配的方案数,即 \(dp[u][0]-=\sum dp[u][i]\times self[i]\) .

注意因为 DFS 的时候, \(dp[u][0]\) 容斥系数是取反的,所以在输出 \(dp[1][0]\) 的时候要取负。

//Author: RingweEH
void Adde( int u,int v ) { e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; }
void bmod( int &x,int y ) { y+=(y<0)*Mod; x+=y-Mod; x+=(x<0)*Mod; }
void DFS( int u,int fat )
{
	siz[u]=1; dp[u][1]=1;
	for ( int i=head[u]; i; i=e[i].nxt )
	{
		int v=e[i].to; if ( v==fat ) continue;
		DFS(v,u);
		for ( int x=0; x<=siz[u]+siz[v]; x++ ) g[x]=0;
		for ( int x=0; x<=siz[u]; x++ )
			for ( int y=0; y<=siz[v]; y++ )
				bmod(g[x+y],1ll*dp[u][x]*dp[v][y]%Mod);
		for ( int x=0; x<=siz[u]+siz[v]; x++ ) dp[u][x]=g[x];
		siz[u]+=siz[v];
	}
	for ( int i=2; i<=siz[u]; i+=2 ) bmod(dp[u][0],Mod-1ll*dp[u][i]*self[i]%Mod);
}

int main()
{
	n=read();
	for ( int i=1,u,v; i<n; i++ ) u=read(),v=read(),Adde(u,v),Adde(v,u);

	self[0]=1;
	for ( int i=2; i<=n; i+=2 ) self[i]=1ll*self[i-2]*(i-1)%Mod;
	DFS(1,0);

	printf("%d\n",Mod-dp[1][0] );

	return 0;
}

F - Robots and Exits

Orz Msea

首先,显然只有一个选择的机器人无效,直接删除。令每个机器人到左边第一个出口的距离为 \(x_i\) ,到右边的距离为 \(y_i\) . 每次移动相当于把 \((x,y)\) 变成 \((x,y+1),(x+1,y)\)\(x=a\) 时就从左边出口出去,反之亦然。

那么可以转化为从原点开始向上或者向右走,那么折线两边的点集就是走左边或者右边的点集,两个方案不同当且仅当某一边的点集不同。

不妨令折线为下点集的轮廓,设 \(dp[i]\) 为折线最后一个点为 \(i\) 的方案数,有

\[dp[i]=1+\sum_{x_j<x_i,y_j<y_i}dp[j] \]

BIT 优化即可,按照 \(x\) 升序,因为是严格 \(<\) 所以还要 \(y\) 降序。

//Author: RingweEH
int main()
{
	n=read(); m=read();
	for ( int i=1; i<=n; i++ ) a[i]=read();
	for ( int i=1; i<=m; i++ ) b[i]=read();

	for ( int i=1; i<=n; i++ )
	{
		if ( a[i]<=b[1] || a[i]>=b[m] ) continue;
		int x=lower_bound(b+1,b+1+m,a[i])-b;
		if ( b[x]==a[i] ) continue;
		p[++cnt]=make_pair(a[i]-b[x-1],b[x]-a[i]); tmp[cnt]=b[x]-a[i];
	}
	sort(tmp+1,tmp+1+cnt); tot=unique(tmp+1,tmp+1+cnt)-tmp-1;
	for ( int i=1; i<=cnt; i++ )
		p[i].se=lower_bound(tmp+1,tmp+1+tot,p[i].se)-tmp;
	sort(p+1,p+1+cnt,cmp); cnt=unique(p+1,p+1+cnt)-p-1;	
	dp[0]=1;
	for ( int i=1; i<=cnt; i++ )
		dp[i]=Query(p[i].se-1)+1,Add(p[i].se,dp[i]);

	int ans=0;
	for ( int i=0; i<=cnt; i++ ) ans=(ans+dp[i])%Mod;
    printf("%d\n",ans);

	return 0;
}
posted @ 2021-05-08 15:35  MontesquieuE  阅读(87)  评论(0编辑  收藏  举报