【题解】P10537 [APIO2024] 九月
题解:P10537 [APIO2024] 九月
题意
在一个树上,在 \(k\) 天内有 \(n-1\) 个节点掉落,会有 \(m\) 个记录者记录掉落的情况,每一天每一个人会以任意的顺序记录当天的掉落情况,求出 \(k\) 的最大值。
思路
根据题意可以得到,判断区间 \([l,r]\) 是否合法,有两个必要的条件。
- 区间 \([l,r]\) 必须在 \(m\) 个人的记录集合中相等。
1 2 3
1 2 4
以上样例就不合法。
- 区间 \([l,r]\) 删除后仍然可以构成一棵树。
第一个性质完全可以用 Hash 来判断。
第二个性质可以使用扫一圈判断每一个节点还有多少个节点未掉,最后判断一下即可。
AC code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n, m;
int solve(int nn, int mm, vector<int>FA, vector<vector<int>>SA) {
//初始化
n = nn - 1, m = mm;
int ans = 0;
vector<int>f(n + 1);
vector<vector<int>>s(m + 1, vector<int>(n + 1));
vector<vector<int>>p(m + 1, vector<int>(n + 1));
vector<pair<ll,ll >>has(m+1);
vector<vector<bool>>vis(m+1,vector<bool>(n+1));
vector<int>cnt(m+1);
for (int i = 1; i <= n; ++i) f[i] = FA[i];
for (int i=1;i<= m; ++i) for (int j=1;j<=n;++j) s[i][j]=SA[i-1][j-1];
for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) ++p[i][f[j]];
for (int j = 1; j <= n; ++j) {
//判断构成的集合相等
for (int i = 1; i <= m; ++i) has[i].first += s[i][j], has[i].second += (ll)s[i][j] * s[i][j],vis[i][s[i][j]]=1;//Hash
bool flag = 1;
pair<ll, ll>q = has[1];
for (int i = 2; i <= m; ++i) {
if (has[i] != q) {
flag = 0;
break;
}
}
//判断是否可以构成一棵树
for (int i = 1; i <= m; ++i) if (p[i][s[i][j]]) ++cnt[i];
for (int i = 1; i <= m; ++i) {
--p[i][f[s[i][j]]];
if (!p[i][f[s[i][j]]] && vis[i][f[s[i][j]]]) --cnt[i];
}
for (int i = 1; i <= m; ++i) flag &= !cnt[i];
if (flag) ++ans;//全部符合
}
return ans;
}

浙公网安备 33010602011771号