题解:P10755 [COI 2022-2023] Netrpeljivost
stannum_114514 · · 题解
感觉这题需要一点“灵光一现”的能力,或者说是集中注意力?
注意到这一个题有一个很好的性质————它是一个满二叉树,这样假如我们对每一层做
然后我们就有了一个很显然的
仔细想想这样转移其实很浪费,中间的点会用很多次,但每次都要重新枚举,我们可以先做一个中转。
把
这样可以做
那么这题就做完了,复杂度
代码。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
void ckmn(auto &x,auto y){if(x>y)x=y;}
const int N=2505;
int n,a[N][N];
struct Node{
int l,r; ll w;
};vector<Node>s[N<<2];
ll vl1[N][N],vl2[N][N],w[N][N],mn1[N],mn2[N];
int a1[N],a2[N],a3[N],a4[N];
int t1,t2,t3,t4;
bool vs[N][N],v1[N],v2[N];
#define ls p<<1
#define rs p<<1|1
void sol(int l,int r,int p){
if(l==r){
s[p].push_back({l,l,0});
return;
} int mid=l+r>>1;
sol(l,mid,ls),sol(mid+1,r,rs);
t1=t2=t3=t4=0;
for(auto u:s[ls]){
w[u.l][u.r]=u.w;
if(!v1[u.l])a1[++t1]=u.l;
if(!v2[u.r])a2[++t2]=u.r;
v1[u.l]=v2[u.r]=true;
}
for(auto u:s[rs]){
w[u.l][u.r]=u.w;
if(!v1[u.l])a3[++t3]=u.l;
if(!v2[u.r])a4[++t4]=u.r;
v1[u.l]=v2[u.r]=true;
}
for(int i=1;i<=t2;++i)
for(int j=1;j<=t3;++j)
w[a2[i]][a3[j]]=a[a2[i]][a3[j]];
for(int i=1;i<=t1;++i)
for(int j=1;j<=t3;++j)
for(int k=1;k<=t2;++k)
ckmn(vl1[a1[i]][a3[j]],w[a1[i]][a2[k]]+w[a2[k]][a3[j]]);
for(int i=1;i<=t1;++i)
for(int j=1;j<=t4;++j)
for(int k=1;k<=t3;++k)
ckmn(vl2[a1[i]][a4[j]],vl1[a1[i]][a3[k]]+w[a3[k]][a4[j]]);
for(int i=1;i<=t1;++i){
for(int j=1;j<=t4;++j){
s[p].push_back({a1[i],a4[j],vl2[a1[i]][a4[j]]});
s[p].push_back({a4[j],a1[i],vl2[a1[i]][a4[j]]});
}
}
for(auto u:s[ls])w[u.l][u.r]=w[0][0],v1[u.l]=v2[u.r]=false;
for(auto u:s[rs])w[u.l][u.r]=w[0][0],v1[u.l]=v2[u.r]=false;
vector<Node>().swap(s[ls]),vector<Node>().swap(s[rs]);
for(int i=1;i<=t1;++i)for(int j=1;j<=t3;++j)
vl1[a1[i]][a3[j]]=vl1[0][0];
for(int i=1;i<=t1;++i)for(int j=1;j<=t4;++j)
vl2[a1[i]][a4[j]]=vl2[0][0];
for(int i=1;i<=t2;++i)for(int j=1;j<=t3;++j)
w[a2[i]][a3[j]]=w[0][0];
}
signed main(){
ios::sync_with_stdio(false);
int i,j,k,l,r,x,y,z;
for(i=1,cin>>n;i<=n;++i)
for(j=1;j<=n;++j)cin>>a[i][j];
memset(vl1,63,sizeof vl1);
memset(vl2,63,sizeof vl2);
memset(w,63,sizeof w);
x=n+1>>1; ll ans=2e18;
sol(1,x,2),sol(x+1,n,3);
for(i=1;i<=n;++i)mn1[i]=mn2[i]=vl1[0][0];
for(auto u:s[2])ckmn(mn1[u.r],u.w);
for(auto u:s[3])ckmn(mn2[u.l],u.w);
for(i=1;i<=n;++i)for(j=1;j<=n;++j)
ckmn(ans,mn1[i]+mn2[j]+a[i][j]);
return printf("%lld\n",ans),0;
}