P10537 [APIO2024] 九月 题解
场外选手来凑热闹。
先考虑
如果
于是签到题就做完了。时间复杂度
参考代码(GNU C++17):
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-6;
int solve(int n,int m,vector<int> f,vector<vector<int> > s){
int c=0;
vector g(m,vector<set<int> >(n));
// 每个志愿者的树
vector v(m,vector<bool>(n));
// 每个志愿者的树里面的结点是否在之前尝试删除过
vector<set<int> > t(m);
// 每个志愿者的树里面有标记的结点
for(int i=0;i<m;i++)
for(int j=1;j<n;j++)
g[i][f[j]].emplace(j);
vector<double> a(m);
// 记录前缀 cos 和
for(int i=0;i<n-1;i++){
bool b=true;
for(int j=0;j<m;j++){
int x=s[j][i];
v[j][x]=true,t[j].emplace(x),a[j]+=cos(x);
// 打标记
if(g[j][x].empty()){
while(x&&v[j][x]&&g[j][x].empty())
t[j].erase(x),g[j][f[x]].erase(x),x=f[x];
} // 可以删除,进行跳父亲删标记
b&=t[j].empty(); // 判断是否有被标记的点
}
for(int j=1;j<m&&b;j++)
b&=fabs(a[j]-a[j-1])<eps;
// 判断前缀构成的集合是否相等
c+=b;
}
return c;
}