GDCPC2024
按照赛后写的顺序。
I
\(a_x\ge a_y+a_z\) 代表有两个必须的条件是 \(a_x>a_y\) 和 \(a_x>a_z\),发现这虽然不是一种偏序,但是它仍然具有传递性,所以建一张 DAG 后 toposort。从最后的点开始依次确定值。时间复杂度 \(O(n+m)\)。
#include<bits/stdc++.h>
#define int long long
#define pii std::pair<int,int>
#define fi first
#define se second
const int maxn=2e5+10;
std::vector<int>a[maxn],f[maxn];
int rd[maxn],topo[maxn],ans[maxn];
std::vector<pii>b[maxn];
int n,m;
bool topo_sort(){
std::queue<int>q;
int cnt=0;
for(int i=1;i<=n;i++) fprintf(stderr,"rd[%lld]=%lld\n",i,rd[i]);
for(int i=1;i<=n;i++) if(rd[i]==0) q.push(i),topo[++cnt]=i;
while(q.size()){
int x=q.front();
q.pop();
for(int v:f[x]) {
rd[v]--;
if(rd[v]==0){
topo[++cnt]=v;
q.push(v);
}
}
}
fprintf(stderr,"cnt=%lld\n",cnt);
return cnt==n;
}
signed main(){
std::cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y,z;
std::cin>>x>>y>>z;
a[x].push_back(y);
a[x].push_back(z);
b[x].push_back({y,z});
f[y].push_back(x);
f[z].push_back(x);
rd[x]+=2;
}
if(!topo_sort()){
printf("-1");
return 0;
}
fprintf(stderr,"topo_sort finish\n");
int sum=0;
for(int i=1;i<=n;i++){
//solve for topo[i]
int mx=1;
for(pii q:b[topo[i]]){
mx=std::max(mx,ans[q.fi]+ans[q.se]);
fprintf(stderr,"ans[%lld]=%lld and ans[%lld]=%lld then mx=%lld\n",q.fi,ans[q.fi],q.se,ans[q.se],mx);
}
ans[topo[i]]=mx;
sum+=mx;
fprintf(stderr,"topo[%lld]=%lld and ans[topo[%lld]]=%lld\n",i,topo[i],i,ans[topo[i]]);
}
if(sum>(int)1e9) printf("-1");
else printf("%lld",sum);
}
C
这应该可以用哈夫曼树做,但那样太麻烦了。
考虑一种类似树形 dp 的方法,从下向上考虑。对于每个点贪心处理一下即可。