以下,斜体表示注意点,粗体表示技巧点。
A
spfa 最长路、环具有特殊性质考虑缩点。
容易发现环上的点可以通过跑很多次直到点权全部为 \(0\),于是缩点跑 spfa 最长路即可。
实现
B
必经边考虑割边,割边考虑边双。
我们发现,必经边是割边的子集。
考虑缩边双,这样缩成的树的边全都是割边。
既然要边最多,选直径即可。
C
图论结合背包模型。
我们可以考虑把 \(p\) 个点对放进很多强连通分量里边。
然后发现这是个 01 背包模型,有 \(n\) 个物品,第 \(i\) 个体积为 \(\frac{i(i-1)}{2}\),价值为 \(i\),现在要最小化总价值。
所以第一问的答案即为 \(dp_p\)。
第二问就很简单了,总共 \(\frac{dp_p(dp_p-1)}{2}\) 对点,减掉 \(p\) 个双向对是单向对个数(一定是最多的,因为去除了不连通的情况)。
实现
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N=2e5+5;
int p;
int dp[N],w[N];signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>p;for(int i=1;i<=p;i++)w[i]=i*(i-1)/2;memset(dp,0x3f,sizeof dp);dp[0]=0,dp[1]=2;for(int i=2;i<=p;i++)for(int j=w[i];j<=p;j++)dp[j]=min(dp[j],dp[j-w[i]]+i);cout<<dp[p]<<' '<<(dp[p]*(dp[p]-1)/2)-p;return 0;
}
D
见题解。