zoukankan      html  css  js  c++  java
  • CF 868 F. Yet Another Minimization Problem

    F. Yet Another Minimization Problem

    http://codeforces.com/contest/868/problem/F

    题意:

      给定一个长度为n的序列。你需要将它分为m段,每一段的代价为这一段内相同的数的对数,最小化代价总和。 n<=100000,m<=20。

    分析:

      f[k][j]=min{f[k-1][j]+cost(k,j,i)};

      cost发现不能快速的算出。于是不能用类似单调队列+二分的方法来做了。

      考虑分治,solve(Head,Tail,L,R,w)当分治区间为Head,Tail,L,R为转移的区间,那么可以直接扫一遍找到转移的最优位置k,然后分治下去。分治的过程中,维护每个数出现了几次(cnt数组),在进入下一层的时候,更新了下层用到的区间的cnt。

    代码:

     1 /*
     2 * @Author: mjt
     3 * @Date:   2018-10-15 11:28:17
     4 * @Last Modified by:   mjt
     5 * @Last Modified time: 2018-10-15 14:40:30
     6 */
     7 #include<cstdio>
     8 #include<algorithm>
     9 #include<cstring>
    10 #include<cmath>
    11 #include<iostream>
    12 #include<cctype>
    13 #include<set>
    14 #include<vector>
    15 #include<queue>
    16 #include<map>
    17 #define fi(s) freopen(s,"r",stdin);
    18 #define fo(s) freopen(s,"w",stdout);
    19 using namespace std;
    20 typedef long long LL;
    21 
    22 inline int read() {
    23     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    24     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    25 }
    26 
    27 const int N = 100005;
    28 
    29 int a[N], cnt[N];
    30 LL f[N], g[N];
    31 
    32 #define add(x) w += cnt[x], cnt[x] ++
    33 #define del(x) cnt[x] --, w-= cnt[x]
    34 
    35 void solve(int Head,int Tail,int L,int R,LL w) { // w保存(L~R)中,非(Head~Tail),区间的值,即L~min(R,Head)。
    36     if (Head > Tail) return ;
    37     int mid  = (Head + Tail) >> 1, p = min(R, mid), k = 0;
    38     for (int i=Head; i<=mid; ++i) add(a[i]);
    39     for (int i=L; i<=p; ++i) {
    40         del(a[i]); // 从i转移,所以i左边的数,不应该被算入贡献,所以要减去。
    41         if (f[mid] > g[i] + w) f[mid] = g[i] + w, k = i;
    42     }
    43 
    44     for (int i=Head; i<=mid; ++i) del(a[i]); 
    45     for (int i=L; i<=p; ++i) add(a[i]);
    46     solve(Head, mid - 1, L, k, w); 
    47     
    48     for (int i=L; i<k; ++i) del(a[i]); 
    49     for (int i=Head; i<=mid; ++i) add(a[i]);
    50     solve(mid + 1, Tail, k, R, w);
    51     
    52     for (int i=Head; i<=mid; ++i) del(a[i]); // 初始为递归进来时候的cnt数组。
    53     for (int i=L; i<k; ++i) add(a[i]);
    54 }
    55 int main() {
    56     int n = read(), k = read();
    57     for (int i=1; i<=n; ++i) {
    58         a[i] = read();
    59         f[i] = f[i - 1] + cnt[a[i]];
    60         cnt[a[i]] ++;
    61     }
    62     memset(cnt, 0, sizeof(cnt));
    63     while (-- k) {
    64         swap(f, g);
    65         memset(f, 0x3f, sizeof(f));
    66         solve(1, n, 1, n, 0);
    67     }
    68     cout << f[n];
    69     return 0;
    70 }
  • 相关阅读:
    lcx
    交换网络中存在的攻击及加固方法概括
    Hello world~
    CCSPSECURE1 安全理论
    SQL注入经验总结
    Access Control List
    初探java集合框架图
    深入浅出分析LinkedHashMap
    红黑树实现分析
    深入浅出的分析TreeMap
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9790888.html
Copyright © 2011-2022 走看看