很有 AT 风格的一道题,神秘的差分约束。
考虑无负环等价于差分约束有解,所以我们给每个点都附一个权值 \(x_i\)。
因为初始边不能删,所以 \(x_i-x_{i+1}\ge 0\)。我们设 \(q_i=x_i-x_{i+1}\ge 0\)。
由于无负环等价于环上正边数量大于负边,所以 \(i<j\) 时,必有 \(x_i-x_j=\sum\limits_{k=i}^{j-1}q_k\ge 1\);反之则有 \(x_j-x_i=\sum\limits_{k=j}^{i-1}q_k\le 1\)。
因为我们想要尽可能的保留下每一条边,所以只有在 \(\sum\limits_{k=i}^{j-1}q_k=0\) 时删除负边,在 \(\sum\limits_{k=j}^{i-1}q_k\ge 2\) 时删除正边。那么这个问题就转化为了构造最优的 \(q\) 数组。
首先由于尽可能保留边,所以 \(q_i\in\{0,1\}\)。然后就有经典 \(dp\) 了。
设 \(dp_{i,j}\) 表示最后一个 \(1\) 在 \(i\) 位置,倒数第二个 \(1\) 在 \(j\) 位置时的最优解。考虑可以从 \(dp_{j,k}\) 推导过来。那么此时新增的值有:
- \(i+1,j+1\) 之间的所有负边。
- \(j+2\) 到 \(i\) 间所有点向 \(1\) 到 \(k\) 间连的所有正边。
- \(i+1\) 这个点向 \(1\) 到 \(j\) 间连的所有正边。
系数可以通过二维前缀和简单求解。之所以有这么多 \(+1,+2\),是因为我们的 \(q\) 数组是差分数组,要比原数组长度少一。时间复杂度 \(O(n^3)\)。(感觉有很强的单调性,能不能使用斜率优化 \(dp\) 优化到 \(O(n^2)\)?)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
int n,dp[N][N],a[N][N],b[N][N],ans;
int as(int xa,int xb,int ya,int yb){return a[xb][yb]-a[xb][ya-1]-a[xa-1][yb]+a[xa-1][ya-1];
}int bs(int xa,int xb,int ya,int yb){return b[xb][yb]-b[xb][ya-1]-b[xa-1][yb]+b[xa-1][ya-1];
}signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0),cin>>n;for(int i=1;i<=n;i++){for(int j=1;j<i;j++) cin>>a[i][j];for(int j=i+1;j<=n;j++) cin>>b[i][j];}for(int i=1;i<=n+1;i++)for(int j=1;j<=n+1;j++){a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];}ans=bs(1,n,1,n);for(int i=1;i<n;i++){for(int j=1;j<i;j++){dp[i][j]=1e18;for(int k=0;k<j;k++)dp[i][j]=min(dp[i][j],dp[j][k]+as(j+2,i,1,k));dp[i][j]+=as(i+1,i+1,1,j)+bs(j+1,i,j+1,i);ans=min(ans,dp[i][j]+bs(i+1,n,i+1,n)+as(i+2,n,1,j));}dp[i][0]=bs(1,i,1,i);ans=min(ans,dp[i][0]+bs(i+1,n,i+1,n));}return cout<<ans,0;
}