题目大意:给定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次即可
注意这题不加读入优化会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;
}
时间: 2024-10-20 02:51:09