神仙题?反正我是完全想不到哇QAQ
这场AGC真的很难咧\(\times 10086\)

\(\bf Description\)

一张 \(n\) 个点的图,\(i\)\(i+1\) 有连边。
现在来了个Snuke,他会给所有 \((i,j) ,i \ne j\) 连边,如果 \(i<j\) ,边权为 \(-1\) ,否则为 \(1\)
然鹅Ringo不想要图里有负环,所以他会删去Snuke加的一些边,使得图中没有负环,删除一条边有个代价,问最小的删边代价。\(3 \leq n \leq 500\)

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

\(\bf Solution\)

(官方题解是从 \(0\) 标号的,我是从 \(1\) 标号的,所以有一点点不一样)
对于一个没有负环的图,我们可以弄出这样一个数组 \(p\) 满足

  • 对于任意 \(i\)\(j\) 的边,满足 \(p_j \leq p_i + weight(i,j)\),(weight是权值,不是代价)

显然这个 \(p_i\) 是存在的,比如说是 \(1\)\(i\) 的最短路。
然后令 \(q_i=p_i-p_{i+1}\) ,于是

  • 对于一条 \(i → j (i>j)\) 的边,必须满足 \(p_j \leq p_i+1\),即 \(q_j+q_{j+1}+ \cdots + q_{i-1} \leq 1\)
  • 对于一条 \(i → j (i<j)\) 的边,必须满足 \(p_j \leq p_i-1\),即 \(q_i+q_{i+1}+ \cdots + q_{j-1} \geq 1\)

可以发现只用考虑 \(0 \leq q_i \leq 1\)的情况 。

现在问题就简单了,对于一个 \(q\) ,只要把不符合上述条件的边都删掉就行。

\(f[i][j]\) 长度为 \(j\) 的数组里最后一个 \(1\)\(j\) ,倒数第二个在 \(i\) ,的最小删边代价。(和官方题解是反的)
当我们从 \(f[i][j]\) 转移到 \(f[j][k]\) 时,要删去这样两种边:

  • \(b → a \ (b>a), i<a \leq j, b>k\) (因为 \(b\)\(a\) 有两个 \(1\) 了所以就不行)
  • \(a → b, j<a<b \leq k\) (因为 \(a\)\(b\) 没有 \(1\) 了所以就不行)

用前缀和就可以 \(O(1)\) 转移啦。
时间复杂度 \(O(n^3)\)

具体实现的话,用 \(w[i][j]\) 表示 \(1 \leq a \leq i , j \leq b \leq n\) ,所有 \(b → a\) 边的权值和
\(vv[i][j]\) 表示 \(i \leq a < b \leq j\) ,所有 \(a → b\) 边的权值和。
预处理一下就可以转移了。

\(q_0\)\(q_{n+1}\) 强制为 \(1\) 可以省去对边界的特判。

#include<bits/stdc++.h>
#define LL long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=505;
const int p=998244353;
int n;
int a[N][N];
LL w[N][N],vv[N][N];
LL f[N][N];

void read(int &x){ scanf("%d",&x); }
void read(LL &x){ scanf("%lld",&x); }

LL vwv(int a,int b,int c){
    return w[b][c]-w[a-1][c];
}

void chkmin(LL &x,LL y){
    if (y<x) x=y;
}

int main(){
    read(n);
    fr(i,1,n)
     fr(j,1,n)
      if (i!=j) read(a[i][j]);
    fr(i,1,n)
     rf(j,n,i+1){
        w[i][j]=w[i][j+1];
        fr(k,1,i) w[i][j]+=a[j][k];
     }
    fr(i,1,n)
     fr(j,i+1,n+1){
        vv[i][j]=vv[i][j-1];
        fr(k,i,j-1) vv[i][j]+=a[k][j];
     }
    memset(f,0x3f,sizeof f);
    f[0][0]=0;
    fr(i,0,n)
     fr(j,i,n)
      if (f[i][j]<1e18){
        fr(k,j+1,n+1)
         chkmin(f[j][k],f[i][j]+vv[j+1][k]+vwv(i+1,j,k+1));
      }
    LL ans=1e18;
    fr(i,0,n) chkmin(ans,f[i][n+1]);
    cout<<ans<<endl;
    return 0;
}
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄