(a[i][j]) 表示([i,j))与其他点相连的边的边权和(就是我们割了环上的边(i,i+1)和(j-1,j))
容易用二维前缀和预处理
然后(f(i,j))是两个矩形取min 通过一些方法递推 看代码吧... 我基本照别人抄的
#include<bits/stdc++.h>
using namespace std;
#define fp(i,l,r) for(register int (i)=(l);(i)<=(r);++(i))
#define fd(i,l,r) for(register int (i)=(l);(i)>=(r);--(i))
#define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
#define mem(a) memset((a),0,sizeof (a))
#define O(x) cerr<<#x<<':'<<x<<endl
#define ll long long
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
void wr(int x){
if(x<0)putchar('-'),x=-x;
if(x>=10)wr(x/10);
putchar('0'+x%10);
}
const int MAXN=7005,inf=1e9;const ll mod=998244353;
inline void tmod(ll &x){x%=mod;}
int dp1[MAXN][MAXN],dp2[MAXN][MAXN],a[MAXN][MAXN],mi[MAXN],n,m;
inline void add(int x1,int x2,int y1,int y2,int z){
a[x1][y1]+=z;a[x1][y2+1]-=z;a[x2+1][y1]-=z;a[x2+1][y2+1]+=z;
}
main(){
n=read();m=read();
fp(i,1,m){
int x=read(),y=read(),z=read();if(x>y)swap(x,y);
add(x,y-1,y,n,z);add(1,x-1,x,y-1,z);
}
fp(i,1,n)fp(j,1,n)
a[i][j]+=-a[i-1][j-1]+a[i-1][j]+a[i][j-1];
fp(i,1,n)mi[i]=inf;
//dp1[i][j]->l in [i,j-1] r in [j,n]
//dp2[i][j]->l in [1,i-1] r in [i,j-1]
fp(i,1,n)fp(j,i+1,n)dp1[i][j]=dp2[i][j]=inf;
fd(j,n,1){
int ans=inf;
fd(i,j-1,1){
mi[i]=min(mi[i],a[i][j]);
dp1[i][j]=ans=min(ans,mi[i]);
}
}
fp(i,1,n)mi[i]=inf;
fp(i,2,n){
int ans=inf;
fp(j,i+1,n){
mi[j-1]=min(mi[j-1],a[i-1][j-1]);
dp2[i][j]=ans=min(ans,mi[j-1]);
}
}
ll ans=0;
fp(i,1,n)fp(j,i+1,n)tmod(ans+=1ll*min(dp1[i][j],dp2[i][j])+2ll*inf);
printf("%lld
",ans);
return 0;
}