POJ3666

题目链接:http://poj.org/problem?id=3666

题目大意:

  有一个由 N 个数组成的数组num,要求通过加减其中元素的数字把它变成一个不减数列或者不增数列。让一个数字加 1 的花费为 1,求最小花费。

AC思路:

  DP题。拿着个假算法搞了半天然后明智地放弃了。思路来源于网上。

  我们先来讨论如何用最小花费让数列变成不减数列。

  dp[i][j] 表示对于前 i 个元素,最大数(也可以理解为是最后一个数)是 j 时的最小花费。则 dp[i][j] = abs(num[i]-j) + min(dp[i-1][k], 0<=k<j).

  Warning! 数据类型要用 long long 否则 WA!

  要离散化。

AC代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <map>
 6 using namespace std;
 7 typedef long long ll;
 8 const int maxn=2000+5;
 9 const ll inf=0x7fffffff;
10 map<ll,int> lists;
11 ll A[maxn],As[maxn];
12 ll dp[maxn][maxn];
13 ll abss(ll a,ll b){
14     if(a>b) return a-b;
15     return b-a;
16 }
17 int main(){
18     int N;
19     scanf("%d",&N);
20     int num=0;
21     for(int i=0;i<N;i++){
22         scanf("%d",&A[i]);
23         if(lists[A[i]]==0){
24             lists[A[i]]=1;
25             As[num++]=A[i];
26         }
27     }
28     sort(As,As+num);
29     for(int i=0;i<num;i++)
30         lists[As[i]]=i;
31     for(int i=0;i<num;i++)
32         for(int j=0;j<N;j++)
33             dp[i][j]=inf;
34     ll ans=inf;
35     for(int i=0;i<N;i++){
36         ll mm;
37         if(i==0)    mm=0;
38         else    mm=dp[i-1][0];
39         for(int j=0;j<num;j++){
40             if(i!=0)    mm=min(mm,dp[i-1][j]);
41             dp[i][j]=abss(As[j],A[i])+mm;
42             if(i==N-1)  ans=min(ans,dp[i][j]);
43         }
44     }
45     printf("%lld\n",ans);
46     return 0;
47 }
时间: 2024-10-28 14:44:25

POJ3666的相关文章

poj3666(Making the Grade)

Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ

【POJ3666】【USACO 2008 Feb Gold】 2.Cow Game 动规

题意:有若干个数,然后可以花费i的代价让某个数+i或者-i. 现在要求让你把序列排成不升或者不降,问最小代价. 题解: 首先可以证明,最优花费下最后所有的数都可以是现在的某个数: 证:如果两个数调整后在两个数中间,那么可以把两个数都变为其中一个数,而代价显然是等同的. 这个出来后就好做了. 我们可以先离散化一下,然后f[i][j]表示第i个数变为j时1~i这些数保持非严格单调的最小花费 转移时f[i][j]不必n*n枚举,可以维护一个前缀最优(非常水),然后O(1)转移. 然后做一遍非升,一遍非

线性DP POJ3666 Making the Grade

Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7347   Accepted: 3415 Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up

Making the Grade(POJ3666)

题目大意: 给出长度为n的整数数列,每次可以将一个数加1或者减1,最少要多少次可以将其变成单调增或者单调减(不严格). 题解: 1.一开始我有一个猜想,就是不管怎么改变,最终的所有数都是原来的某个数.然而我并不会证明,然而我属于那种不彻底弄清楚就不会去写的那种顽固分子,于是就脱了好几天.网络上有很多关于此题的题解,确实用了这个猜想来离散化,但是都是讲怎么dp,然后最后扯一句“由于数据比较大,可以离散化”之类的话,要么就是相当粗略的证明(也许已经说的够清楚了只不过我没理解...). 2.今天早上起

POJ3666:Making the Grade——题解

http://poj.org/problem?id=3666 题目大意:给n个数,每次操作可使一个数+1或-1,求最小操作数使得序列不下降或不上升. —————————————————————— 思路:http://blog.csdn.net/luovilonia/article/details/44004041 因为我再讲什么也没什么好讲的了. 但是这人的代码是错的……请注意查找最长不上升和不下降所要减的值是不一样的. #include<cstdio> #include<cstring

poj3666序列对应——DP

题目:http://poj.org/problem?id=3666 很普通的DP,离散化(sort)一下即可: mn的求法很不错(比我原来开了mn[]--简洁). 代码如下: #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int n,a[2005],l[2005],f[20

【POJ3666】Making the Grade 离散化+DP

学到了一个引理:在满足S最小化的条件下,一定存在一种构造序列B的方案,使得序列B中的数值都来自于A中.(数学归纳法+中位数定理得证) 对于状态的表示来说,首先肯定有一个 i ,表示选到了第 i 个数时对应的最优解,由于需要维护序列单调性,因此需要再在状态中加入一个因素 j ,表示在第 i 位选了离散化后的A[ j ]. 状态转移为\(dp[i][j]=min\{dp[i-1][k],k\in[1,j]\}+|A[i]-B[j]|\) 代码如下: #include <cstdio> #inclu

POJ3666Making the Grade[DP 离散化 LIS相关]

Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6445   Accepted: 2994 Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up

Codeforces Round #371 (Div. 1)

A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给出的01序列相等(比较时如果长度不等各自用0补齐) 题解: 1.我的做法是用Trie数来存储,先将所有数用0补齐成长度为18位,然后就是Trie的操作了. 2.官方题解中更好的做法是,直接将每个数的十进制表示中的奇数改成1,偶数改成0,比如12345,然后把它看成二进制数10101,还原成十进制是2