码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForces - 868F Yet Another Minimization Problem

时间:2018-06-15 23:31:34      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:memset   print   inf   +=   names   efi   long   std   stat   

Description

给定一个长度为 \(n(n\le 10^5)\) 的数列,第 \(i\) 个数是 \(a_i\in[1,n]\) ,要求将其划分为 \(k(2\le k\le min(20,n))\) 段以后每段价值和最小。

定义一段的价值为该段相同数的数对个数。

Solution

定义 \(calc(l,r)\)\([l,r]\) 这一段的价值, \(dp[j][i]\) 为前 \(i\) 个数划分为 \(j\) 段的最小价值。那么显然有

\[ dp[j][i]=min\{dp[j-1][i']+calc(i'+1,i),i'<i\} \]

因为 \(dp[j][i]\) 仅由 \(dp[j-1][i']\) 转移来,不妨设 \(j\) 固定。

\(f(i)\) 表示 \(i\) 对应的最优决策点 \(i'\)打表不难发现 \(f(i)\) 单调递增。

考虑分治。\(solve(l,r,L,R)\) 表示对于 \(i\in [l,r]\) ,有 \(f(i)\in {L,R}\) 。枚举出 \(mid=\cfrac{l+r}{2}\) 的决策点 \(f(mid)\) 后分治 \(solve(l,mid-1,L,f(mid))\)\(solve(mid+1,r,f(mid),R)\) 即可。

对于 \(calc(l,r)\) ,因为 \(l\)\(r\) 的每次移动后都可以 \(O(1)\) 计算答案,所以可以莫队。

#include<bits/stdc++.h>
using namespace std;

template <class T> inline void read(T &x) {
    x = 0; static char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >= '0' && ch <= '9'; ch = getchar()) (x *= 10) += ch - '0';
}

#define N 100001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define ll long long

const ll INF = 0x3f3f3f3f3f3f3f3f, P = 1e9 + 7;
int n, K, a[N], now, nxt = 1, lf = 1, ri, cnt[N];
ll dp[2][N], sum;

inline void calc(int l, int r) {
    while (ri < r) sum += cnt[a[++ri]], cnt[a[ri]]++;
    while (ri > r) cnt[a[ri]]--, sum -= cnt[a[ri--]];
    while (lf > l) sum += cnt[a[--lf]], cnt[a[lf]]++;
    while (lf < l) cnt[a[lf]]--, sum -= cnt[a[lf++]];
}

#define mid (l + r >> 1)
void solve(int l, int r, int L, int R) {
    if (l > r) return;
    dp[nxt][mid] = INF;
    int t;
    rep(i, L, min(mid, R)) {
        calc(i, mid);
        if (dp[nxt][mid] > dp[now][i - 1] + sum) dp[nxt][mid] = dp[now][i - 1] + sum, t = i;
    }
    solve(l, mid - 1, L, t), solve(mid + 1, r, t, R);
}

int main() {
    read(n), read(K);
    rep(i, 1, n) read(a[i]);
    memset(dp, INF, sizeof dp); dp[now][0] = 0;
    while (K--) solve(1, n, 1, n), swap(now, nxt);
    printf("%lld", dp[now][n]);
    return 0;
}

CodeForces - 868F Yet Another Minimization Problem

标签:memset   print   inf   +=   names   efi   long   std   stat   

原文地址:https://www.cnblogs.com/aziint/p/9189225.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!