混沌DM

DM Hunter

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

http://codeforces.com/contest/269/problem/B

题目意思

  n颗植物,种类有m种。种在一个长度无限的实数轴上。

  现在可以通过改变一些植物的坐标,使得最后所有植物的种类沿x轴正方向为不下降序列。

  求最少要改变多少植物的位置。

解法一:

  这是我现场的解法,复杂度O(n*m)

  dp[i][j],表示到第j颗植物,使其以种类i结尾,最少需要改变的数量。

  dp[1][j],特殊算出。

  dp[i][0] = 0

  dp[i][j] = min(dp[i-1][k] + sum[j][i] - sum[k][i])  |  0<=k<=j)  = min(dp[i-1][k] - sum[k][i]) | 0<=k<=j) + sum[j][i]

  sum[j][k]表示编号1..k中有多少种类为j的植物

 

  看起来复杂度像是m*n*n,不过,其实min(dp[i-1][k] - sum[k][i])这个,一边DP,一边算就可以了,因为k的范围是越来越大嘛。

 

  这题植物的坐标是没什么用的,因为一定是严格递增的,而实际上,任意两个实数之间可以种下无数棵。所有需要改变的植物,拔走后,最后再考虑就可以了。

比赛时的代码比较SB,还写单调队列来优化空间。。实际上没比滚动数组优化。。而实际上,不优化内存也完全够。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<iostream>
 7 #include<algorithm>
 8 #include<queue>
 9 using namespace std;
10 int a[5010],dp[5010],sum[5010];
11 int l,r,d[5010];
12 int n,m;
13 int main()
14 {
15     while (~scanf("%d%d",&n,&m))
16     {
17         for(int i=1;i<=n;i++)scanf("%d%*lf",a+i);
18         dp[0]=0;
19         for(int i=1;i<=n;i++)
20             dp[i]=dp[i-1] + (a[i]!=1);
21         for(int i=2;i<=m;i++){
22             for(int j=1;j<=n;j++)
23                 sum[j]=sum[j-1]+(a[j]!=i);
24             l=0;r=-1;
25             for(int j=n;j>=0;j--){
26                 while(l<=r && dp[j]-sum[j]<=dp[d[r]]-sum[d[r]])r--;
27                 d[++r]=j;
28             }
29             for(int j=n;j>0;j--){
30                 while(d[l]>j)l++;
31                 dp[j]=dp[d[l]]-sum[d[l]]+sum[j];
32             }
33         }
34         printf("%d\n",dp[n]);
35     }
36     return 0;
37 }

解法二:贪心

  植物的种类构成一个序列

  ans = n - len(最长不下降子序列)

最长不下降子序列有nlogn解法,网上资料也很多,就不再重复。

posted on 2013-02-03 23:05  混沌DM  阅读(405)  评论(0编辑  收藏  举报