首页 > 其他分享 >P6277 [USACO20OPEN] Circus P

P6277 [USACO20OPEN] Circus P

时间:2024-10-09 22:15:22浏览次数:9  
标签:return USACO20OPEN int ll Circus ans P6277 include MOD

做法来自浙江队长,因为其他的题解我一篇都看不懂。

考察一条极长的二度链 C,即左右端点度数不为 \(2\),中间的点度数都等于 \(2\),它把整张图分成了左右两部分 A 和 B(端点既属于 AB 也属于 C)。如果 \(|C| \ge n - k\),那么 A 和 B 都一定被占满了,C 上的点一定会阻挡 A 和 B 之间互换,所以可以分解成两个子问题。特殊的,钦定递归 A 时 C 上的奶牛都在靠近 B 的一边,递归 B 时都在靠近 A 的一边,这样每次递归时 \(n - k\) 不变。

令 \(r = |C| - n + k\),即 C 上的奶牛数。他们之间的顺序是固定了的,所以方案数为 \(\dbinom{k}{r}r!\),然后分解成 A 和 B 两个子问题后,分配到两边的方案数是 \(\dbinom{n-r}{A}\)。当分解到联通块内没有 \(|C| \ge n - k\) 的链时,联通块内两两可交换,方案数是 \(1\)。

动态的过程不好维护,考虑对每个部分在递归到最底层时统计。本质上是多重组合数,每个联通块贡献 \(\dfrac{1}{cow_i!}\),每条断掉的边贡献的系数和阶乘抵消所以不用考虑,最后乘上 \(k!\) 即可。

计算每个联通块最后的奶牛数:断开每条极长链时会新增 \(n - k - 1\) 个空白点,但是要去掉最后一次断开,则有 \(cow_i = siz_i + out_i \cdot (n-k-1)-(n-k)\)。从大到小枚举 \(k\),则相当于不断加边。维护 \(siz_i\) 和 \(out_i\) 即可。

// They say that life is always easier
// After you let yourself come undone
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
struct Node {
	int u, v, w;
} E[N];
int n, cnt, deg[N], dsu[N], siz[N], out[N];
ll fac[N], ifac[N], ans[N];
set<int> st;
vector<int> G[N];
void Dfs(int u, int fat, int lst, int sum) {
	if(deg[u] != 2) {
		if(lst) E[++cnt] = {lst, u, sum};
		st.insert(lst = u), sum = 1;
	}
	for(int v : G[u]) if(v != fat)
		Dfs(v, u, lst, sum + 1);
}
ll Pow(ll a, int p = MOD - 2) {
	ll ans = 1;
	for(; p; p >>= 1, a = a * a % MOD)
		if(p & 1) ans = ans * a % MOD;
	return ans;
}
ll C(int n, int m) {
	if(n < 0 || m < 0 || n < m) return 0;
	return fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}
int Find(int u) {
	if(u == dsu[u]) return u;
	return dsu[u] = Find(dsu[u]);
}
void Solve() {
	cin >> n;
	for(int i = 1; i < n; ++i) {
		int u, v; cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		++deg[u], ++deg[v];
	}
	for(int i = 1; i <= n; ++i) if(deg[i] != 2) {
		Dfs(i, 0, 0, 1); break;
	}
	for(int i = 1; i <= n; ++i)
		dsu[i] = i, siz[i] = 1, out[i] = deg[i];
	sort(E + 1, E + cnt + 1, [](Node a, Node b) {
		return a.w < b.w;
	});
	fac[0] = 1;
	for(int i = 1; i <= n; ++i)
		fac[i] = fac[i - 1] * i % MOD;
	ifac[n] = Pow(fac[n]);
	for(int i = n - 1; i >= 0; --i)
		ifac[i] = ifac[i + 1] * (i + 1) % MOD;
	ans[n] = fac[n], ans[n - 1] = fac[n - 1];
	int now = 1;
	for(int k = n - 2; k >= 1; --k) {
		while(now <= cnt && E[now].w < n - k) {
			int x = Find(E[now].u), y = Find(E[now].v);
			dsu[x] = y, siz[y] += siz[x] + E[now].w - 2;
			out[y] += out[x] - 2, ++now, st.erase(x);
		}
		ans[k] = fac[k]; int r = k;
		for(int i : st) {
			int s = siz[i] + (n - k - 1) * out[i] - (n - k);
			ans[k] = ans[k] * ifac[s] % MOD, r -= s;
		}
	}
	for(int i = 1; i <= n; ++i) printf("%lld\n", ans[i]);
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("data.in", "r", stdin);
	freopen("code.out", "w", stdout);
#endif
	cin.tie(0)->sync_with_stdio(0);
	int t = 1; //cin >> t;
	while(t--) Solve();
	return 0;
}

标签:return,USACO20OPEN,int,ll,Circus,ans,P6277,include,MOD
From: https://www.cnblogs.com/Aria-Math/p/18455199

相关文章

  • 题解:P9954 [USACO20OPEN] Cowntact Tracing B
    考虑暴力。枚举让每头牛都当一次“零号病人”和\(K\)的所有组合,模拟感染的过程,检查得出的病人是否和给出的一样即可。代码:#include<bits/stdc++.h>usingnamespacestd;boolinfectedd[101];intN,cowx[251],cowy[251];boolcheck(intpatient_zero,intK){ boolinfect......
  • 题解:P9953 [USACO20OPEN] Social Distancing II B
    解决思路:根据奶牛的位置对数组进行排序。计算相邻健康奶牛和感染奶牛之间的最小距离。这个距离值减一用来估计感染传播的半径。(确保了感染奶牛之间的距离在当前半径下不会导致传播给其他健康奶牛。)遍历排序后的奶牛列表,找到每一段连续感染奶牛的区域,并计算这些区域中可能需要的......
  • CodeForces 1C - Ancient Berland Circus
    先通过三点确定一条直线,然后算出三条向量的夹角,与圆心角对比,如果呈倍数关系,说明可以接受。特别注意EPS1e-2和1e-7过不了全部数据,改成1e-4通过全部数据。点击查看代码#include<bits/stdc++.h>#definedoublelongdoubleusingnamespacestd;constdoublePI=acos(-1);......
  • [USACO20OPEN] Exercise P
    有意思的计数题。题目链接题意求所有长度为\(n\)的排列的所有环长的\(\text{lcm}\)的乘积。\(n\leq7500\)解法先min-max容斥把\(\text{lcm}\)换成\(\gcd\)。求\(\prod\limits_{\sigma}\prod\limits_{T\neq\emptyset}\gcd(T)^{(-1)^{|T|}}\),其中\(T\)表......
  • luogu P6276 [USACO20OPEN]Exercise P
    题面传送门首先考虑一个固定排列的答案是什么。考虑它的若干置换环,应该是所有环环长的LCM,所有数都会转回本来的位置。现在变成计算所有环的环长的LCM的积的问题。注意......
  • Codeforces 1 C. Ancient Berland Circus
    题意:二维平面中,给定三个点,这三个点是正多边形的三个顶点,求正多边形最小的面积。思路:两对点分别求中垂线,相交点是多边形外接圆的圆心,圆心有了半径和角度也就有了,之后求一......
  • [USACO20OPEN]Sprinklers 2_ Return of the Alfalfa(dp)
    先讲一下等会要用到的定义:红格代表被甜玉米洒水器喷洒到的方格,蓝格代表被苜蓿洒水器喷洒到的方格。橙格代表有甜玉米洒水器的方格,紫格代表有苜蓿洒水器。\((a,b)\)......
  • Mathematical Circus-数论-分类讨论
    codeforces MathematicalCircus-div2-B题意:给定n,k。是否能把(1--n)的数分成符合条件的(a,b)对。条件:(a+k)*b%4==0解:因为:原式=(a+k)*b≡0(mod4)ab+b*k≡0(mod4)若k>=4,b......
  • CF1C Ancient Berland Circus
    给定\(3\)个点,求以这\(3\)个点为顶点的正多边形面积最小值。先以这张图为例,首先可以肯定圆的半径是确定的。根据秦九韶公式,有\(S_{\triangleABC}=\sqrt{p(p-a)(p......
  • CF1719B Mathematical Circus
    题链:cfluogu分类讨论思想。Description把\(1\)到\(n\)共\(n\)个整数分成\(\frac{n}{2}\)对有序数对\(\left(a_i,b_i\right)\),则对于\(\forall\left(a_i,......