题目大意:给定n个人,需要分k次过河,两个人i,j如果同乘一条船就会产生ai,j的代价,求最终代价的最小值

这个玩应显然满足四边形不等式(虽然我并不知道这个不等式是啥
然后就是决策单调(虽然我并不知道为何满足四边形不等式一定决策单调
然后就能分治做辣。。。
定义Solve(l,r,optl,optr)表示当前在处理区间[l,r],最优决策区间为[optl,optr]
然后我们用区间[optl,min(optr,mid−1)]的f值来更新f[mid],并记录最优决策点pos
那么[l,mid−1]部分的最优决策一定在[optl,pos],[mid+1,r]部分的最优决策一定在[pos,optr]
递归做下去就行了,时间复杂度O(nlogn)
做k<script type="math/tex" id="MathJax-Element-51">k</script>次即可

注意这题不加读入优化会T掉。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 4040
using namespace std;
int n,k;
int a[M][M],f[880][M];
int Sum(int x,int y)
{
    return a[y][y]+a[x-1][x-1]-a[x-1][y]-a[y][x-1];
}
void Solve(int f[],int g[],int l,int r,int opt_l,int opt_r)
{
    if(l>r) return ;
    int i,mid=l+r>>1,pos=opt_l;
    g[mid]=0x3f3f3f3f;
    for(i=opt_l;i<=min(opt_r,mid-1);i++)
        if(f[i]+Sum(i+1,mid)<g[mid])
            g[mid]=f[i]+Sum(i+1,mid),pos=i;
    Solve(f,g,l,mid-1,opt_l,pos);
    Solve(f,g,mid+1,r,pos,opt_r);
}
namespace IStream{
    #define L (1<<16)
    char buffer[L],*S,*T;
    char Get_Char()
    {
        if(S==T)
        {
            T=(S=buffer)+fread(buffer,1,L,stdin);
            if(S==T) return EOF;
        }
        return *S++;
    }
    int Get_Int()
    {
        char c=Get_Char();
        while( c<'0' || c>'9' )
            c=Get_Char();
        return c-'0';
    }
}
int main()
{
    //freopen("321E.in","r",stdin);
    //freopen("321E.out","w",stdout);
    int i,j;
    cin>>n>>k;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            a[i][j]=IStream::Get_Int()+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        }
    for(i=1;i<=n;i++)
        f[1][i]=Sum(1,i);
    for(i=2;i<=k;i++)
        Solve(f[i-1],f[i],i,n,i-1,n-1);
    cout<<f[k][n]/2<<endl;
    return 0;
}