zoukankan      html  css  js  c++  java
  • Levko and Array

    题意:

    有一长度为n的正整数序列,你可以选择K个数字任意改变它,使得$max { a(i+1) - a(i) } $ 最小,求最小值。

    解法:

    1.$O(n^2log(MAX_A) )$,考虑二分出$d = max { a(i+1) - a(i) } $,这样考虑dp

    $f(i,j)$表示前i个数字,末位的数字为j的时候最少修改了多少数字

    $f(i,j) = min { f(i-1,k) } (j-d ≤ k ≤ j+d,j = a(i))$

    $f(i,j) = min { f(i-1,k) } (j-d ≤ k ≤ j+d,j ≠ a(i))$

    注意到有效的j只有$a(i),a(i)-d,a(i)+d$,从而对第二维离散化,同时用单调队列维护区段min即可

    (维护方法,对于 前面出现的 比后面的数字小 的数一定不会出现在答案中,这样只要维护一个单调增的双端队列即可)

    此方法常数过大,TLE

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <ctime>
     6 
     7 #define LL long long
     8 #define N 2010
     9 #define INF 0x3f3f3f3f
    10 
    11 using namespace std;
    12 
    13 int n,m,K,minh,maxh,tots;
    14 int a[N],a0[N*3];
    15 int f[N][N*3],q[N*3];
    16 double tott;
    17 
    18 int Abs(int x)
    19 {
    20     if(x<0) return -x;
    21     return x;
    22 }
    23 
    24 bool check(int d)
    25 {
    26     a0[0]=0;
    27     for(int i=1;i<=n;i++)
    28     {
    29         a0[++a0[0]]=a[i];
    30         if(a[i]-(LL)d>=(LL)minh) a0[++a0[0]]=a[i]-d;
    31         if(a[i]+(LL)d<=(LL)maxh) a0[++a0[0]]=a[i]+d;
    32     }
    33     sort(a0+1,a0+a0[0]+1);
    34     m=1;
    35     for(int i=2;i<=a0[0];i++) if(a0[i]!=a0[i-1]) a0[++m]=a0[i];
    36     for(int i=1;i<=m;i++) f[1][i]=1;
    37     int t1=lower_bound(a0+1,a0+m+1,a[1])-a0;
    38     f[1][t1]=0;
    39     int st=1,ed=0;
    40     for(int i=2;i<=n;i++)
    41     {
    42         st=1, ed=0;
    43         int tmp=1,minv=K+1;
    44         for(int j=1;j<=m;j++)
    45         {
    46             while(tmp<=m && a0[tmp]<=a0[j]+d)
    47             {
    48                 while(st<=ed && f[i-1][q[ed]]>=f[i-1][tmp]) ed--;
    49                 q[++ed]=tmp++;
    50             }
    51             while(st<ed && a0[q[st]]<a0[j]-d) st++;
    52             int k=q[st];
    53             if(a0[j]==a[i]) f[i][j]=f[i-1][k];
    54             else f[i][j]=f[i-1][k]+1;
    55             minv = min(minv, f[i][j]);
    56             if(f[i][j] + n-i <= K) return 1;
    57         }
    58         if(minv > K) return 0;
    59     }
    60     return 1;
    61 }
    62 
    63 int main()
    64 {
    65     freopen("test.txt","r",stdin);
    66     while(~scanf("%d%d",&n,&K))
    67     {
    68         unsigned int l=0,r=0;
    69         a0[0]=0;
    70         minh=INF;
    71         maxh=-INF;
    72         for(int i=1;i<=n;i++)
    73         {
    74             scanf("%d",&a[i]);
    75             minh=min(minh,a[i]);
    76             maxh=max(maxh,a[i]);
    77             if(i>1) r = max(r,(unsigned int)Abs(a[i]-a[i-1]));
    78         }
    79         while(r-l>2)
    80         {
    81             unsigned int mid=(l+r)>>1;
    82             if(check(mid)) r=mid;
    83             else l=mid;
    84         }
    85         for(unsigned i=l;i<=r;i++)
    86             if(check(i))
    87             {
    88             //    cout << clock()/1000.0 << endl;
    89                 cout << i << endl;
    90                 break;
    91             }
    92     }
    93     return 0;
    94 }
    View Code

    2.注意到方法一中第二维实际只有 j=a(i) 和其他的j ,两种j。

    从而设$f(i)$表示前i个数字,数字i不改变 最少修改了多少数字。

    这样有

    $f(i) = min {  f(j) + j-i-1 }, ( frac{|a(i)-a(j)|}{i-j} ≤ d )$

    (i到j之间的数字全都改变)

    小常数飘过

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <ctime>
     6 
     7 #define LL long long
     8 #define N 2010
     9 #define INF 0x3f3f3f3f
    10 
    11 using namespace std;
    12 
    13 int n,m,K,a[N];
    14 int f[N];
    15 
    16 LL Abs(LL x)
    17 {
    18     if(x<0) return -x;
    19     return x;
    20 }
    21 
    22 bool check(int d)
    23 {
    24     f[1]=0;
    25     if(n-1<=K) return 1;
    26     for(int i=2;i<=n;i++)
    27     {
    28         f[i]=i-1;
    29         for(int j=1;j<i;j++)
    30             if(Abs(a[i]-(LL)a[j]) <= d*(LL)(i-j))
    31                 f[i] = min(f[i], f[j]+i-j-1);
    32         if(f[i]+n-i<=K) return 1;
    33     }
    34     return 0;
    35 }
    36 
    37 int main()
    38 {
    39 //    freopen("test.txt","r",stdin);
    40     while(~scanf("%d%d",&n,&K))
    41     {
    42         LL l=0,r=0;
    43         for(int i=1;i<=n;i++)
    44         {
    45             scanf("%d",&a[i]);
    46             if(i>1) r = max(r,(LL)Abs(a[i]-a[i-1]));
    47         }
    48         while(r-l>2)
    49         {
    50             LL mid=(l+r)>>1;
    51             if(check(mid)) r=mid;
    52             else l=mid;
    53         }
    54         for(unsigned i=l;i<=r;i++)
    55             if(check(i))
    56             {
    57                 cout << i << endl;
    58                 break;
    59             }
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    呵呵
    数据类型转换方法
    工业设计三原则
    C#实现的根据年月日计算星期几的函数
    网页设计的12种颜色
    SqlParameter 存储过程
    HTTP 状态响应码
    Android获取屏幕高度和宽度
    Android屏幕自适应解决方案
    Nodejs学习笔记nodejs的安装
  • 原文地址:https://www.cnblogs.com/lawyer/p/6498566.html
Copyright © 2011-2022 走看看