zoukankan      html  css  js  c++  java
  • 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] imes dp[v][j]) ,注意 (dp[u][0]) 要去掉自匹配的方案数,即 (dp[u][0]-=sum dp[u][i] imes 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
    ",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
    ",ans);
    
    	return 0;
    }
    
    天光渐亮。
  • 相关阅读:
    移动端字体单位
    我像素的理解
    了解viewport概念
    移动端知识
    本地存储和会话存储
    一屏滚动滚轮事件
    关于jquery的笔记
    关于bind()方法
    [css] 滚动条样式问题
    [element-ui] 表格功能实现(删除选中)
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/14745151.html
Copyright © 2011-2022 走看看