• DP经典 BZOJ 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生


    BZOJ 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 419  Solved: 278

    Description

    有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000。现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k。那总的不河蟹度就是所有段的不河蟹度的总和。

    Input

    第一行:两个整数N,M

    第2..N+1行:N个整数代表每个奶牛的编号

    Output

    一个整数,代表最小不河蟹度

    Sample Input

    13 4
    1
    2
    1
    3
    2
    2
    3
    4
    3
    4
    3
    1
    4

    Sample Output

    11
     1 /*因为这个题目分组是没有限制的,所以我们DP方程不能把分组作为一个状态
     2 正解:最差情况每个数位于一段,ans=n,所以若有一段区间内不同的数的数量<=sqrt(n),否则结果一定不是最优。
     3 nsqrt(n)求法:维护b[j],c[j],f[j],pre[j]数组。
     4 b[j]表示b[j]+1...i有j个不同的数的区间的最左端。
     5 那么可以知道f[i]=min{f[i],f[b[j]]+j*j};这样时间复杂度就降了下来
     6 如何维护b[j]数组,当i向后移动一位的时候,pre[a[i]]记录a[i]出现的最后一个位置是哪里?
     7 那么:i++后,pre[a[i]]<=b[j],说明b[j]+1...到i这段序列的不同数的数目就是j+1了,我们用c[j]来记录这个情况,顺便更新pre[a[i]],而且始终维护c[j]==j;
     8 那么b[j]仍然是符合题意的。
     9 维护c[j]就要从b[j]+1开始向后面删除数据,删除时判断若pre[a[t]]>t,则说明是删除了相同的数,对于最后的和谐值没有影响,所以还要删数
    10 知道pre[a[t]]<=t,删除a[t],顺便更新b[j]的位置
    11 */
    12 #define N 40100
    13 #include<iostream>
    14 using namespace std;
    15 #include<cstdio>
    16 #include<cmath>
    17 #include<cstring>
    18 int f[N],b[N],c[N],pre[N],a[N];
    19 int n,m;
    20 void input()
    21 {
    22     scanf("%d%d",&n,&m);
    23     for(int i=1;i<=n;++i)
    24       scanf("%d",&a[i]);
    25     memset(pre,-1,sizeof(pre));/*别忘了设置为-1,因为下面会与b[j]==0的初值进行比较*/
    26     memset(f,127,sizeof(f));
    27 }
    28 void chuli()
    29 {
    30     int sqrtn=sqrt(n+0.5);
    31     f[0]=0;/*初始化,前0个数的不和谐值为0,*/
    32     for(int i=1;i<=n;++i)
    33     {
    34         for(int j=1;j<=sqrtn;++j)
    35         {
    36             if(pre[a[i]]<=b[j])
    37               c[j]++;/*统计新加入的数是不是符合要求*/
    38         }
    39         pre[a[i]]=i;/*更新pre*/
    40         for(int j=1;j<=sqrtn;++j)
    41         {
    42             if(c[j]>j)/*删除数,缩短序列*/
    43             {
    44                 int t=b[j]+1;
    45                 while(pre[a[t]]>t) ++t;
    46                 b[j]=t;c[j]--;
    47             }
    48         }
    49         for(int j=1;j<=sqrtn;++j)
    50           f[i]=min(f[i],f[b[j]]+j*j);/*更新f*/
    51     }
    52 }
    53 int main()
    54 {
    55     input();
    56     chuli();
    57     cout<<f[n]<<endl;
    58     return 0;
    59 }
    60 /*这个题目既然不以划分次数为状态,那么可以考虑,划分序列的长度*/
  • 相关阅读:
    PHP array_intersect_uassoc
    PHP array_intersect_key
    PHP array_intersect_assoc
    PHP array_flip
    PHP array_filter
    PHP array_fill
    PHP array_fill_keys
    Android4.0-Fragment框架实现方式剖析
    Fragment 生命周期
    WebView
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5504705.html
Copyright © 2020-2023  润新知