[AGC036D] Negative Cycle

一、题目

点此看题

二、解法

首先有一个根本想不到的题意转化:不存在负环等价于存在一组合法的差分约束的解

设差分约束的合法解是 x1,x2...xn,我们可以把所有边转化成不等式。图上初始的 n1 条边,带来的限制是 xixi+1,可以进一步转化为差分:qi=xixi+10

对于边 ij(i<j),满足 xi1xj,即 xixj1,那么 qi+qi+1...qj11,也就是差分数组在 [l,r) 的区间和如果 1,那么边 lr 就可以保留。换句话说如果区间和 =0 那么需要删去。

对于边 ij(i>j),满足 xi+1xj,即 xjxi1,那么 qj+qj+1...qi11,也就是差分数组在 [l,r) 的区间和如果 1,那么边 rl 就可以保留。换句话说如果区间和 2 那么需要删去。

不难发现如果 qi2,那么可以调整成 qi=1,不难发现答案不变劣,所以最终的答案 qi={0,1}

那么我们可以规划每个位置上的 qi,然后删去不合法的边。根据代价计算的特性,我们可以定义 f[i][j] 表示考虑前 i 为个位置,其中 qi=1,上一个等于 1 的位置是 j,需要删去边的最小权值。转移枚举 k,考虑如何计算代价。

考虑左右端点都在 (j,i] 中的第一类边是需要删去的。左端点在 (k,j],右端点在 (i,n] 的第二类边是需要删去的,这可以需处理二维前缀和轻松计算,时间复杂度 O(n3)

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 505;
#define int long long
const int inf = 1e18;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,ans,a[M][M],b[M][M],f[M][M];
void upd(int &x,int y) {x=min(x,y);}
int val(int k,int j,int i)
{
	return b[j+1][i]+a[n][j]-a[i][j]-a[n][k]+a[i][k];
}
signed main()
{
	n=read();ans=inf;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(i^j) a[i][j]=read();
	for(int l=n;l>=1;l--)
		for(int r=l;r<=n;r++)
			b[l][r]=b[l+1][r]+b[l][r-1]
				-b[l+1][r-1]+a[l][r];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
	for(int i=1;i<n;i++)
	{
		f[i][0]=val(0,0,i);
		upd(ans,f[i][0]+val(0,i,n));
		for(int j=1;j<i;j++)
		{
			f[i][j]=inf;
			for(int k=0;k<j;k++)
				upd(f[i][j],f[j][k]+val(k,j,i));
			upd(ans,f[i][j]+val(j,i,n));
		}
	}
	printf("%lld\n",ans);
}
posted @   C202044zxy  阅读(236)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2021-04-02 [多校联考2021] 模拟赛3
点击右上角即可分享
微信分享提示