题解 [AGC036D] Negative Cycle

传送门

首先基本可以确定是 DP
但是状态是难以划分的
又是非人力之可为系列
考虑一个图中不存在负环?那就存在最短路啊
因为边权为 0 的那些边的存在,有 \(dis_{i}\geqslant dis_{i+1}\)
因为图中边权都是 \(\pm 1\),所以有 \(dis_{i+1}\geqslant dis_{i}-1\)
那么发现最短路相等的点构成若干个区间,尝试对这个东西(就是最短路的差分数组)做 DP
\(f_{i, j}\) 考虑区间 \([1, j]\),最靠右的 \(-1\)\(j\),第二在 \(i\) 且没有负环的最小代价
这个状态可以转移到 \(f_{j, k}\),要删去一些存在会打破当前最短路性质的边

image

这个可以二维前缀和优化
复杂度 \(O(n^3)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 510
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
ll a[N][N], b[N][N], f[N][N], sum, ans=INF;

signed main()
{
	n=read();
	memset(f, 0x3f, sizeof(f));
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) if (i!=j) sum+=(a[i][j]=read()), b[i][j]=a[i][j];
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) a[i][j]+=a[i][j-1];
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) a[i][j]+=a[i-1][j];
	for (int i=1; i<=n; ++i) {
		ll tem=0;
		for (int s=1; s<=i; ++s)
			for (int t=s+1; t<=i; ++t)
				tem+=b[s][t];
		f[0][i]=tem;
	}
	for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) b[i][j]+=b[i][j-1];
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) b[i][j]+=b[i-1][j];
	for (int i=0; i<=n; ++i) {
		for (int j=i+1; j<=n; ++j) if (f[i][j]!=INF) {
			for (int k=j+1; k<=n; ++k) {
				ll tem=0;
				tem+=a[k][i]-a[j][i];
				tem+=b[k][k]-b[j][k];
				f[j][k]=min(f[j][k], f[i][j]+tem);
				// printf("f[%d][%d] min= f[%d][%d](%lld)+%lld\n", j, k, i, j, f[i][j], tem);
			}
		}
	}
	for (int i=1; i<=n; ++i) ans=min(ans, f[i][n]);
	printf("%lld\n", ans);
	
	return 0;
}
posted @ 2022-07-04 07:14  Administrator-09  阅读(4)  评论(0编辑  收藏  举报