codeforces 321E Ciel and Gondolas 四边形不等式

题目大意:给定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

codeforces 321E Ciel and Gondolas 四边形不等式的相关文章

Codeforces 321E Ciel and Gondolas

传送门:http://codeforces.com/problemset/problem/321/E [题解] 首先有一个$O(n^2k)$的dp. # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long lon

【CodeForces】【321E】Ciel and Gondolas

DP优化/四边形不等式 这题……跟邮局那题简直一模一样吧……好水的E题…… 设dp[i][j]表示前 i 艘“gondola”坐了前 j 个人,那么方程即为$dp(i,j)=min\{ dp[i-1][k]+w[k][j] \} (i\leq k\leq j)$ 很明显$w(l,r)=\sum_{i=l}^r \sum_{j=l}^r u(i,j) /2$是满足四边形不等式的……那么根据决策单调性直接搞就行了…… 1 //CF 321E 2 #include<vector> 3 #includ

四边形不等式优化

四边形不等式优化条件(转自这里) 在动态规划中,经常遇到形如下式的转台转移方程: m(i,j)=min{m(i,k-1),m(k,j)}+w(i,j)(i≤k≤j)(min也可以改为max) 上述的m(i,j)表示区间[i,j]上的某个最优值.w(i,j)表示在转移时需要额外付出的代价.该方程的时间复杂度为O(N^3). 下面我们通过四边形不等式来优化上述方程,首先介绍什么是"区间包含的单调性"和"四边形不等式" (1)区间包含的单调性:如果对于i≤i'<j≤

四边形不等式(石子合并)

动态规区间dp做这道题的话应该是n^3,下面的代码优化到了n^2,用四边形不等式优化. 设mid[i][j]是dp[i][j]的最优解的断点,即它左区间的右端点,那么mid[i][j-1]<=mid[i][j]<=mid[i+1][j],所以在求解dp[i][j]时,枚举k可以只枚举这两个值之间枚举就好, 程序要先枚举区间长度,在枚举左端点,枚举每个区间长度时,他们的k总是只从1到n,只走一遍,所以这就相当于优化了一层,变成了O(n2)的. 比如len长度为3时,dp[1][3]只会枚举mid

【四边形不等式】POJ1160[IOI2000]-Post Office

[题目大意] v个村庄p个邮局,邮局在村庄里,给出村庄的位置,求每个村庄到最近邮局距离之和的最小值. [思路] 四边形不等式,虽然我并不会证明:( dp[i][j]表示前i个村庄建j个邮局的最小值,w[i][j]表示在i到j之间建立一个邮局的最小值.w[i][j]显然取i~j的中位数,可以在O(1)时间内求出. 显然dp[i][j]=min{dp[k][j-1]+w[k+1][i]}. 傻傻写错i和j…… 1 #include<iostream> 2 #include<cstdio>

四边形不等式优化DP——石子合并问题 学习笔记

好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 求出将n堆石子合并成一堆的最小得分和最大得分以及相应的合并方案. 设m[i,j]表示合并d[i..j]所得到的最小得分. 状态转移方程: 总的时间复杂度为O(n3). [优化方案] 四边形不等式: m[i,j]满足四边形不等式 令s[i,j]=max{k | m[

UVa 10003 (可用四边形不等式优化) Cutting Sticks

题意: 有一个长为L的木棍,木棍中间有n个切点.每次切割的费用为当前木棍的长度.求切割木棍的最小费用. 分析: d(i, j)表示切割第i个切点到第j个切点这段所需的最小费用.则有d(i, j) = min{d(i, k) + d(k, j)} + a[j] - a[i]; ( i < k < j ) 最后一项是第一刀的费用. 时间复杂度为O(n3) 最后还要注意一下输出格式中整数后面还要加一个句点. 1 //#define LOCAL 2 #include <iostream>

51nod 1022 石子归并 V2(四边形不等式)

分析:记dp[i][j]为从i到j合并的最小代价(顺时针,i可以大于j),sum[i][j]为从i到j的和,则dp[i][j]=min{dp[i][k-1]+dp[k][j]}+sum[i][j],(i<k<=j),直接求的话复杂度为O(n^3),会T. 四边形不等式优化:记s[i][j]为dp[i][j]取得最小值时对应的k值,则有dp[i][j]=min{dp[i][k-1]+dp[k][j]}+sum[i][j],(s[i][j-1]<=k<=s[i+1][j]),可以证明,

HDU 2829 Lawrence (斜率优化DP或四边形不等式优化DP)

题意:给定 n 个数,要你将其分成m + 1组,要求每组数必须是连续的而且要求得到的价值最小.一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0. 析:DP状态方程很容易想出来,dp[i][j] 表示前 j 个数分成 i 组.但是复杂度是三次方的,肯定会超时,就要对其进行优化. 有两种方式,一种是斜率对其进行优化,是一个很简单的斜率优化 dp[i][j] = min{dp[i-1][k] - w[k] + sum[k]*sum[k] - sum[k]*sum[