zoukankan      html  css  js  c++  java
  • bzoj千题计划235:bzoj2448: 挖油

    http://www.lydsy.com/JudgeOnline/problem.php?id=2448

    一遍过,嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎,O(∩_∩)O~

    题意是最小化最大值

    设计区间dp

    dp[i][j] 表示在能确定x不在区间[i,j]内,或确定x在区间[i,j]内某个位置的最坏情况下的最小值

    dp[i][j]=min { max(dp[i][k-1],dp[k+1][j] ) + a[k] }  k∈[i,j]

    O(n^3)复杂度

    #include<cstdio>
    #include<cstring>
    #include<iostream>
     
    using namespace std;
     
    #define N 2002
     
    int a[N];
     
    int dp[N][N];
     
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
     
    int main()
    {
        int n;
        read(n);
        for(int i=1;i<=n;++i) read(a[i]);
        memset(dp,63,sizeof(dp));
        for(int i=1;i<=n;++i)
            dp[i][i]=a[i],dp[i][i-1]=0;
        for(int i=n;i;--i)
            for(int j=i;j<=n;++j)
                for(int k=i;k<=j;++k)
                    dp[i][j]=min(dp[i][j],max(dp[i][k-1],dp[k+1][j])+a[k]);
        printf("%d",dp[1][n]); 
    } 
    
    View Code

    优化:

    把max去掉,就可以使用单调队列优化了

    很显然的结论是长区间的dp值一定>=它的子区间的dp值

    当固定i和j时,随着k的递增,dp[i][k-1]单调不降,dp[k+1][j]单调不增

    所以一定可以找到一个分界点g,

    当k∈[i,g]时,dp[i][k-1]>dp[k+1][j]

    当k∈[g+1,j]时,dp[k+1][j]>dp[i][k-1]

    所以上述转移方程变为

    当k∈[i,g]时,dp[i][j]=min { dp[i][k-1]+a[k] }

    当k∈[g+1,j]时,dp[i][j]=min { dp[k+1][j]+a[k] }

    用g[i][j]表示对于每对i,j 求出的g

    对于 当k∈[i,g[i][j] ]时,dp[i][j]=min { dp[i][k-1]+a[k] }

    可以得出结论 g[a][b]<=g[a][b+1]

    因为这里是前面的dp值>后面的dp值,[a,b+1]在[a,b]后面加了一个位置,

    后面的dp值不变或增大,前面要包含更多的位置使前面变的更大,才能>=后面,所以g的位置不变或后移

    所以固定区间左端点,随右端点的右移,g单调不减

    对于 当k∈[g[i][j]+1,j]时,dp[i][j]=min { dp[k+1][j]+a[k] }

    可以得出结论 g[a-1][b]<=g[a][b]

    因为这里是后面的dp值>前面的dp值,[a-1,b]在[a,b]前面加了一个一个位置

    前面的dp值不变或增大,后面要包含更多的位置使后面变的更大,才能>=前面,所以g的位置不变或前移

    所以固定区间右端点,随左端点的左移,g单调不增

    所以可维护n+1个单调队列

    一个表示固定左端点,n个表示固定右端点

    因为是左端点从n倒序枚举,右端点从左端点正序枚举

    所以固定左端点的只需要用一个,左端点改变的时候清空队列即可

    但是右端点是跳来跳去的,所以要用n个

    实际实现的时候可以不计算g

    如果要计算g的话,由上面可以得出结论

    g[a-1][b]<=g[a][b]<=g[a][b+1]

    利用g的单调性计算g

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    #define N 2002
    
    int a[N];
     
    int dp[N][N];
    
    int q[N][N];
    int h[N],t[N];
     
    #define A(x) dp[i][(x)-1]+a[(x)]
    #define B(x) dp[(x)+1][j]+a[(x)]
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
     
    int main()
    {
        int n;
        read(n);
        for(int i=1;i<=n;++i) read(a[i]);
        memset(dp,63,sizeof(dp));
        for(int i=n;i;--i)
        {
            dp[i][i]=a[i];
            h[0]=0;
            q[0][t[0]=1]=i;
            q[i][t[i]=1]=i;
            for(int j=i+1;j<=n;++j)
            {
                while(h[0]<t[0] && A(q[0][h[0]])<B(q[0][h[0]])) ++h[0];
                while(h[0]<t[0] && A(j)<A(q[0][t[0]-1])) --t[0];
                q[0][t[0]++]=j;
                while(h[j]<t[j] && B(q[j][h[j]])<A(q[j][h[j]])) ++h[j];
                while(h[j]<t[j] && B(i)<B(q[j][t[j]-1])) --t[j];
                q[j][t[j]++]=i;
                dp[i][j]=min(A(q[0][h[0]]),B(q[j][h[j]]));
            }
        }
        printf("%d",dp[1][n]); 
    } 

    2448: 挖油

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 133  Solved: 57
    [Submit][Status][Discuss]

    Description

    给出一条线段,在左端点点0与右端点n+1间有n个点(n<=2000),并且在0到x之间的所有点都是有油的,在每个点钻井判断是否有油需要时间ti,求能够知道x的最坏情况下最少需要多少时间。
     

    Input

    第一行包含一个数n,如题目描述。
    第二行包含n个数,表示在第i个点钻井判断是否有油需要的时间。
     

    Output

    输出包含一行,最坏情况下最少需要多少时间。
     

    Sample Input

    4
    8 24 12 6

    Sample Output

    42

    HINT

    对于100%的数据,n<=2000,ti<=10^6

  • 相关阅读:
    UE4_简易AI_玩家死亡动画bug修复
    UE4_简易AI_Ai攻击
    pikachu-SSRF
    pikachu-XXE漏洞
    pikachu-PHP反序列化
    pikachu-Over permission(越权漏洞)
    pikachu-不安全的文件下载和上传
    pikachu-File Inclusion(文件包含漏洞)
    Web安全之RCF(远程命令,代码执行漏洞)
    Web安全之SQL Inject 2
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8446072.html
Copyright © 2011-2022 走看看