bzoj 1200: [HNOI2005]木梳 DP

1200: [HNOI2005]木梳

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 266  Solved: 125
[Submit][Status]

Description

Input

第一行为整数L,其中4<=L<=100000,且有50%的数据满足L<=104,表示木板下侧直线段的长。第二行为L个正整数A1,A2,…,AL,其中1

Output

仅包含一个整数D,表示为使梳子面积最大,需要从木板上挖掉的格子数。

Sample Input

9
4 4 6 5 4 2 3 3 5

Sample Output

3

  一般的贪心策略还是需要较严格的证明的。比如这道题,位置pos所处的可能高度应该是h[i]+/-1  (pos-2<=i<=pos+2)稍有疏忽,就会将i的范围搞错。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define MAXN 110000
#define INFL 0x3f3f3f3f3f3f3f3fLL
typedef long long qword;
int h[MAXN];
int pp[MAXN][32];;
qword dp[MAXN][2][32];
inline void deal(qword &x,qword y)
{
        if (x<y)x=y;
}
int main()
{
        freopen("input.txt","r",stdin);
        int i,j,k,k2,x,y,z,n,m;
        qword sum=0;
        scanf("%d",&n);
        for (i=1;i<=n;i++)
        {
                scanf("%d",h+i);
                sum+=h[i];
                for (j=h[i]-1;j<=h[i]+1;j++)
                {
                        pp[i][++pp[i][0]]=j;
                        if (i-1>=1)pp[i-1][++pp[i-1][0]]=j;
                        if (i+1<=n)pp[i+1][++pp[i+1][0]]=j;
                        if (i-2>=1)pp[i-2][++pp[i-2][0]]=j;
                        if (i+2<=n)pp[i+2][++pp[i+2][0]]=j;
                }
        }
        for (i=1;i<=n;i++)
        {
                sort(pp[i]+1,pp[i]+pp[i][0]+1);
                pp[i][0]=unique(&pp[i][1],&pp[i][pp[i][0]+1])-pp[i]-1;
                for (j=pp[i][0]+1;j<12;j++)pp[i][j]=0;
                while (pp[i][0] && pp[i][pp[i][0]]>h[i])pp[i][pp[i][0]--]=0;
        }
        for (i=0;i<=n+1;i++)
                for (j=0;j<2;j++)
                        for (k=0;k<32;k++)
                                dp[i][j][k]=-INFL;
        for (i=1;i<=pp[1][0];i++)
                dp[1][0][i]=dp[1][1][i]=pp[1][i];
        for (i=2;i<=n;i++)
        {
                for (j=1;j<=pp[i-1][0];j++)
                {
                        for (k=1;k<=pp[i][0];k++)
                        {
                                if (pp[i-1][j]<pp[i][k])
                                {
                                        deal(dp[i][0][k],dp[i-1][1][j]+pp[i][k]);
                                }else if (pp[i-1][j]>pp[i][k])
                                {
                                        deal(dp[i][1][k],dp[i-1][0][j]+pp[i][k]);
                                }else
                                {
                                        deal(dp[i][0][k],dp[i-1][0][j]+pp[i][k]);
                                        deal(dp[i][1][k],dp[i-1][1][j]+pp[i][k]);
                                }
                        }
                }
        }
        qword ans=-INFL;
        for (i=1;i<=pp[n][0];i++)
        {
                ans=max(ans,dp[n][0][i]);
                ans=max(ans,dp[n][1][i]);
        }
        printf("%lld",sum-ans);
}
时间: 2024-08-01 16:10:47

bzoj 1200: [HNOI2005]木梳 DP的相关文章

BZOJ 1087状态压缩DP

状态压缩DP真心不会写,参考了别人的写法. 先预处理出合理状态, 我们用二进制表示可以放棋子的状态,DP[I][J][K]:表示现在处理到第I行,J:表示第I行的状态,K表示现在为止一共放的棋子数量. #include<stdio.h> #include<iostream> #define N 1111 using namespace std; typedef long long ll; int num,n,m; ll dp[11][1<<11][90]; int hh

BZOJ 1237 配对(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1237 题意:给出两个n元素的数列A和B.为A中的每个元素在B中为其找一个配对的元素(配对的元素不能相等,B中每个元素只能被使用一次),使得所有配对的两个数的差的绝对值之和最小? 思路:首先排序,若无配对元素不能相等这一 限制,则排序后一一匹配即可.有了这个限制,那么对于相等的元素就要在其前后进行调整,显然,与距离较远的调整不如与距离近的调整优.那么,需要在多大的 范围内调整才能保证最优

bzoj 3437 斜率优化DP

写题解之前首先要感谢妹子. 比较容易的斜率DP,设sum[i]=Σb[j],sum_[i]=Σb[j]*j,w[i]为第i个建立,前i个的代价. 那么就可以转移了. 备注:还是要感谢妹子. /************************************************************** Problem: 3437 User: BLADEVIL Language: C++ Result: Accepted Time:3404 ms Memory:39872 kb **

BZOJ 1200 木梳

Description Input 第一行为整数L,其中4≤L≤100000,且有50%的数据满足L≤104,表示木板下侧直线段的长.第二行为L个正整数A1,A2,…,AL,其中Ai≤108 Output 仅包含一个整数D,表示为使梳子面积最大,需要从木板上挖掉的格子数. Sample Input 9 4 4 6 5 4 2 3 3 5 Sample Output 3 HINT 初看此题,这不是一道很水很水的dp题吗,一看数据范围马上枪毙.然后就放肆想,思考一下午未果,打了一发卡决策的dp,50

[BZOJ 3791] 作业 【DP】

题目链接:BZOJ - 3791 题目分析 一个性质:将一个序列染色 k 次,每次染连续的一段,最多将序列染成 2k-1 段不同的颜色. 那么就可以 DP 了,f[i][j][0|1] 表示到第 i 个位置,染了 j 段,当前这一段颜色为 0|1 的最大价值. f[i][][] 只与 f[i-1][][] 有关,第一维用滚动数组就可以了. 代码 #include <iostream> #include <cstdio> #include <cstring> #inclu

[BZOJ 2165] 大楼 【DP + 倍增 + 二进制】

题目链接:BZOJ - 2165 题目分析: 这道题我读了题之后就想不出来怎么做,题解也找不到,于是就请教了黄学长,黄学长立刻秒掉了这道题,然后我再看他的题解才写出来..Orz 使用 DP + 倍增 ,用状态 f[x][i][j] 表示从 i 出发,坐 x 次电梯到达 j ,最多能上升的层数.开始读入的就是 f[1][][] 数组.(注意:若开始时 i 不能走到 j , 则 f[1][i][j] = -INF) 使用倍增,用 f[x][][] 求出 f[x << 1][][] , 一直求f[2

BZOJ 4380 [POI2015]Myjnie | DP

链接 BZOJ 4380 题面 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了. 请给每家店指定一个价格,使得所有人花的钱的总和最大. Input 第一行包含两个正整数n,m(1<=n<=50,1<=m<=4000). 接下来m行,每行包含三个正整数a[i],b[i],ci Output 第

BZOJ 1040: [ZJOI2008]骑士 [DP 环套树]

传送门 题意:环套树的最大权独立集 一开始想处理出外向树树形$DP$然后找到环再做个环形$DP$ 然后看了看别人的题解其实只要断开环做两遍树形$DP$就行了...有道理! 然后洛谷时限再次不科学,卡常失败$SAD$ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; co

BZOJ 1564: [NOI2009]二叉查找树( dp )

树的中序遍历是唯一的. 按照数据值处理出中序遍历后, dp(l, r, v)表示[l, r]组成的树, 树的所有节点的权值≥v的最小代价(离散化权值). 枚举m为根(p表示访问频率): 修改m的权值 : dp(l, r, v) = min( dp(l, m-1, v) + dp(m+1, r, v) + p(l~r) + K ) 不修改(m原先权值≥v) : dp(l, r, v) = min( dp(l, m-1, Value(m)) + dp(m+1, r, Value(m)) + p(l~