zoukankan      html  css  js  c++  java
  • Making the Grade(POJ3666)

    题目大意:

    给出长度为n的整数数列,每次可以将一个数加1或者减1,最少要多少次可以将其变成单调增或者单调减(不严格).

     

    题解:

    1.一开始我有一个猜想,就是不管怎么改变,最终的所有数都是原来的某个数。然而我并不会证明,然而我属于那种不彻底弄清楚就不会去写的那种顽固分子,于是就拖了好几天。网络上有很多关于此题的题解,确实用了这个猜想来离散化,但是都是讲怎么dp,然后最后扯一句“由于数据比较大,可以离散化”之类的话,要么就是相当粗略的证明(也许已经说的够清楚了只不过我没理解...)。

    2.今天早上起来洗漱的时候,感觉头脑比较清醒,再次想了一下这个问题,想到一个自认为正确的证明:

    记原来的数从小到大排序后分别是$a_1 a_2 a_3cdots a_n$ 修改后从左到右分别是$b_1 b_2 b_3cdots b_n$. 为了方便描述,在数轴上标出这些点,称为关键点。 

    假设存在$a_s<b_i<=b_{i+1}<=cdots <=b_j<a_{s+1}$    

    情况一:如果这些b都相等,那么把这些b都改成$a_s$或者$a_{s+1}$ 肯定会有一种更优。

    情况二:如果不全相等,那么肯定存在 $b_p b_{p+1} b_{p+2}cdots b_q$,他们的值相等,那么把他们移到左边的关键点或者右边的关键点,肯定有一种会更加优. 不断这样移动,最后就变成情况一了。

    综上至少存在一种最优方案,最终的所有数都是原来的某个数。

    因此可以离散化之后做dp,dp[i][j]表示把前i个数变成单调增(不严格)且第i个数变成原来第j大的数的最小代价。

    dp[i][j]=min{dp[i-1][1...j]}+abs(a[i]-b[j]).

    单调减(不严格)的情况也一样,更加方便的是可以把原数组倒转后做单调增的dp。

    另外这题和CF Codeforces Round #371 (Div. 1)的C题类似,有个超简单的nlogn做法。可以看这篇:http://www.cnblogs.com/vb4896/p/5894578.html

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <map>
     8 #include <cstdlib>
     9 #include <set>
    10 using namespace std;
    11 
    12 #define X first
    13 #define Y second
    14 #define Mod 1000000007
    15 #define N 3010
    16 typedef long long ll;
    17 typedef pair<int,int> pii;
    18 
    19 inline int Mul(int x,int y){return 1ll*x*y%Mod;}
    20 inline int Add(int x,int y){return ((x+y)%Mod+Mod)%Mod;}
    21 
    22 int n,m;
    23 int a[N],b[N];
    24 ll dp[N][N],Ans=1ll<<60;
    25 
    26 void Solve()
    27 {
    28     for (int j=1;j<=m;j++) dp[1][j]=abs(b[j]-a[1]);
    29     for (int i=2;i<=n;i++)
    30     {
    31         ll tmp=1ll<<60;
    32         for (int j=1;j<=m;j++)
    33         {
    34             tmp=min(tmp,dp[i-1][j]);
    35             dp[i][j]=abs(b[j]-a[i]);
    36             dp[i][j]+=tmp;
    37 
    38         }
    39     }
    40     for (int j=1;j<=m;j++) Ans=min(Ans,dp[n][j]);
    41 }
    42 
    43 int main()
    44 {
    45     //freopen("in.in","r",stdin);
    46     //freopen("out.out","w",stdout);
    47 
    48     scanf("%d",&n);
    49     for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]=a[i]-i;
    50     sort(b+1,b+n+1); 
    51     for (int i=1;i<=n;i++) if (i==1 || b[i]!=b[i-1]) b[++m]=b[i];
    52     
    53     Solve();
    54     printf("%I64d
    ",Ans);
    55     
    56     return 0;
    57 }
  • 相关阅读:
    io学习
    asp.net文件上传进度条研究
    asp.net页面中的Console.WriteLine结果如何查看
    谨慎跟随初始目的不被关联问题带偏
    android 按钮特效 波纹 Android button effects ripple
    安卓工作室 日志设置
    安卓工作室 文件浏览器 android studio File browser
    一个新的Android Studio 2.3.3可以在稳定的频道中使用。A new Android Studio 2.3.3 is available in the stable channel.
    新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial
    码云,git使用 教程-便签
  • 原文地址:https://www.cnblogs.com/vb4896/p/5877962.html
Copyright © 2011-2022 走看看