csp-s2019 总结

D1

T1

不谈

T2

可以先考虑在序列上的情况,考虑对于一个 ),设 (f[i]) 表示以 i 结尾的答案是多少,有:(f[i]=f[j]+1),其中 j 是可以与 i 匹配的前一个位置。然后可以用栈来维护,然后再拓展到树上就行了。。。然后就是记录一下操作然后回朔就行了。。。

T3

写了再写

D2

T1

其实是挺明显的容斥题目的,然后在考场上时我又想过容斥但不知道为什么不了了之(算了,就当是我右边的人的锅^^)。

考虑 dp,首先可以知道肯定只有一个食材是超了的,于是可以枚举这个食材,然后可以再以横行为阶段进行 dp。。。

然后可以设 (f[i][j][h][k]) 表示第 i 列超了,选到第 j 行,i 列有 h 个,其他有 k 个的方案数。。

然后可以发现我们不用管具体h,k是多少,只用关心他们的差就行了,然后就可以优化状态。。。

然后到最后一行时,k>0 的情况即是要求的,然后中间可能有负数,然后平移一下就好。。

T2

呃,首先可以发现一个结论:最优解同时一定也是所有合法解中最后一段的和最小的解。

然后就是求:(f_i=min{S_i-S_jmid S_i-S_jgeq f_j}) (f_i) 表示i结尾的最后一段的长度。

然后一看就可以单调队列优化。。。按 (s_i+f_i) 来维护单调队列就行了。。。

所以我当时为什么用这个性质写了个 (n^2) dp?

然后100分要写高精,订正时可以用__int128水,然后会炸空间,然后可以最后再求和。。

T3

树的重心的性质:

1.删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心;(我觉得这个性质应该是比定义要直观具体好用的)

2.树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等;

3.两个树通过一条边合并,新的重心在原树两个重心的路径上;

4.树删除或添加一个叶子节点,重心最多只移动一条边;

然后首先这题肯定是要对每个点分别求贡献的。。

首先我们可以求出整体的重心,然后以它为根。。

考虑对于一个非根的点 x,删什么它会有贡献。。

首先肯定不可以删它子树的边,这个易证。。

然后考虑如果删非它子树的边:

(S) 表示删掉一条边后的另一棵树的大小。。(g_x) 表示 x 的最大儿子的大小。。

然后有:

[2 imes g_xleq n-S\ 2 imes (n-sz_x-S)leq n-S ]

然后整理可得:

[n-2 imes sz_xleq Sleq n-2 imes g_x ]

然后这就可以用树状数组区间求值了。。

然后考虑如何维护这个树状数组。。

考虑删的边和 x 的关系:

1.是 x 的儿子,这种情况即使S满足要求也不算,要再减去。。

2.是 x 的祖先,这种情况 (S=n-sz_y),可以 dfs 时维护。

3.和 x 没啥关系,这种情况 (S=sz_y),这种情况可以一开始就add进去。。

然后 dfs 的步骤:

这个dfs时我觉得看做边为主体要清晰些。。。

code:

void dfs2(int x,int fa){
	add(0,n-sz[x],1);维护 2 的情况
	if(x!=rt){
		ans+=x*ask(0,n-2*g[x]);
		ans-=x*ask(0,n-2*sz[x]-1);把 1,2,3的情况都算上去
		ans+=x*ask(1,n-2*g[x]);
		ans-=x*ask(1,n-2*sz[x]-1);
		if(z[fa]) z[x]=1;
		ans+=rt*(sz[x]<=n-2*sz[z[x]?v:u]);
	}
	add(0,sz[x],-1);维护1,因为接下来要dfs的就是x的儿子了,S就要变
	add(1,sz[x],1);
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==fa) continue;
		dfs2(y,x);
	}
	add(0,sz[x],1);要回溯时这条边就从2成了3。。
	add(0,n-sz[x],-1);
	if(x!=rt){
        ans-=x*ask(1,n-2*g[x]);
        ans+=x*ask(1,n-2*sz[x]-1);用可减性减去1的情况。。
    }
}

然后就是考虑x=rt的情况:

设rt的儿子中子树最大的节点为u,次大的节点为v。

若割掉的边在u的子树中,则需要满足:(2 imes s_v le n – S)

即:(S le n – 2s_v)

否则,需要满足:(2 imes s_u le n – S)

即:(S le n – 2s_u)

可以在 dfs 的时候直接维护。

这题总体思路和天天爱跑步有点类似,都是推式子然后在树上维护求答案,然后都利用了有些数据在树上的可减性来求子树中的值。。

本题应该也可以算是换根吧?

做这种题一定要把所有可能情况讨论清楚,然后再去处理。。。

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+7;
template <class I>
inline void read(I &x){
    int f=1;
    char c;
    for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+(c&15),c=getchar());
    x*=f;
}
int head[N],nxt[2*N],ver[2*N],tot=1,n,g[N];
int sz[N],rt,t[2][N],ans,u,v;
bool z[N];
inline void add(int x,int y){
	ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
inline void add(int o,int x,int v){
	x++;
	while(x<=n+1){
		t[o][x]+=v;
		x+=x&-x;
	}
}
inline int ask(int o,int x){
	int res=0;
	x++;
	while(x){
		res+=t[o][x];
		x-=x&-x;
	}
	return res;
}
void dfs(int x,int fa){
	sz[x]=1,g[x]=0;
	bool fg=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==fa) continue;
		dfs(y,x);
		sz[x]+=sz[y];
		g[x]=max(g[x],sz[y]);
		if(g[x]>n/2) fg=0;
	}
	if(n-sz[x]>n/2) fg=0;
	if(fg) rt=x;
}
void dfs2(int x,int fa){
	add(0,n-sz[x],1);
	if(x!=rt){
		ans+=x*ask(0,n-2*g[x]);
		ans-=x*ask(0,n-2*sz[x]-1);
		ans+=x*ask(1,n-2*g[x]);
		ans-=x*ask(1,n-2*sz[x]-1);
		if(z[fa]) z[x]=1;
		ans+=rt*(sz[x]<=n-2*sz[z[x]?v:u]);
	}
	add(0,sz[x],-1);
	add(1,sz[x],1);
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==fa) continue;
		dfs2(y,x);
	}
	add(0,sz[x],1);
	add(0,n-sz[x],-1);
	if(x!=rt){
        ans-=x*ask(1,n-2*g[x]);
        ans+=x*ask(1,n-2*sz[x]-1);
    }
}
void solve(){
	read(n);
	ans=0;
	for(int i=1;i<=n;i++)
		head[i]=sz[i]=g[i]=0;
	tot=1;
	for(int i=1;i<n;i++){
		int x,y;
		read(x),read(y);
		add(x,y),add(y,x);
	}
	dfs(1,0);
	dfs(rt,0);
	u=0,v=0;
	for(int i=head[rt];i;i=nxt[i]){
        int x=ver[i];
        if(sz[x]>sz[v]) v=x;
        if(sz[v]>sz[u]) swap(u,v);
    }
    for(int i=1;i<=n+1;i++) t[0][i]=t[1][i]=0;
    for(int i=1;i<=n;i++) add(0,sz[i],1),z[i]=0;
    z[u]=1;
	dfs2(rt,0);
	printf("%lld
",ans);
}
signed main(){
	int T;	
	read(T);
	while(T--){
		solve();
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Hikigaya/p/11891169.html