6546. 【GDOI2020模拟4.8】USACO 2020 Open Contest, Platinum(circus)

题目描述

Farmer John 马戏团的 N 头奶牛( 1 ≤ N ≤ 10^5 )正在准备她们接下来的演出。演出在一棵结点编号为 1 … N 的树上进行。演出的“起始状态”可以定义为一个整数 1 ≤ K ≤ N 以及奶牛 1 … K 在树上的结点分布,使得没有两头奶牛位于相同的结点。 在一场演出中,奶牛们可以进行任意次数的“移动”。在一次移动中,一头奶牛从她的当前所在结点移动到一个未被占据的相邻结点。称两个起始状态是等价的,如果一个状态可以通过一系列移动到达另一个。
对于每一个 1 ≤ K ≤ N ,帮助奶牛们求出起始状态的等价类数量:即可选出的起始状态的最大数量,使得两两不等价。由于这些数字可能很大,输出模 10^9 + 7 的余数。

N ≤ 10^5

题解

很神奇的题目

猜结论,k只奶牛的位置不影响结果,最大数量只与奶牛间是否能交换有关,若干奶牛可以交换则只算一次

证明不会

所以可以假设k只奶牛都是当前深度最大的,只需要维护是否能交换即可,视作边

选一个度数>=3的点做根,如果没有就是链

关系有根与根之间的,父子间的以及兄弟(父亲不是根节点)间的,其余的关系可通过这三种得到

设编号从下往上从小到大,显然k=n-1和n时答案为k!

当k=n-2时,除编号为n-1的儿子以外,其余的根均相连

k<=n-3时所有根相连

当k<=n-2时兄弟相连

对于每个点x设dis[x]表示x向上到某个度数>=3的点的距离,因为根节点的度数>=3所以必然存在

所以x与儿子相连的条件是dis[x]+2<=n-k,即把向上的一段移开并多出两个来交换

只可能向上,因为如果要在一个非根节点处向另一棵子树走的话,父亲边+走上来的边+走下去的边已经有至少三条了

对于每种情况在考虑一下两端的出现时间,以及根的话要考虑父亲的出现时间,可以建一个0点来连

最后变成若干条边,每条边有出现时间,求每个时间的连通情况,线段树分治+可撤销并查集即可

code

#include 
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a tr[400001];
bool bz[100001];

ll qpower(ll a,int b) {ll ans=1;while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}

void bfs()
{
	int i,j,k,l;
	
	h=0;t=1;d[1]=root;
	while (hdp[Y]) swap(X,Y);
	fa[X]=Y;
	if (dp[X]2) {root=i;break;}
	
	if (!root) {fo(i,1,n) printf("%lld\n",jc[i]);return 0;}
	
	bfs();
	dfs(0,root,0);
	ans=1;
	work(1,1,n);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

你可能感兴趣的:(6546. 【GDOI2020模拟4.8】USACO 2020 Open Contest, Platinum(circus))