CF868F Yet Another Minimization Problem

CF868F Yet Another Minimization Problem

题面

链接

题解

转移方程非常套路

然后可以发现可以决策单调性

由于每次转移的贡献不能O(1)算,显然应该考虑分治实现

贡献可以考虑像莫队一样移

复杂度不会证

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0' || ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f*x;
}

#define ll long long
#define re register

const int MAXN = 1e5 + 10;

int a[MAXN];
ll dp[20 + 2][MAXN];
ll cnt[MAXN];
int L,R,n,k;
ll ans;

inline void update(int x,int d)
{
    ans += 1LL * d * (cnt[a[x]]) * (cnt[a[x]]-1)/2;
    return;
}

inline ll calc(int l,int r)
{
    while(l<L) L--,update(L,-1),cnt[a[L]]++,update(L,1); 
    while(l>L) update(L,-1),cnt[a[L]]--,update(L,1),L++;
    while(r<R) update(R,-1),cnt[a[R]]--,update(R,1),R--;
    while(r>R) R++,update(R,-1),cnt[a[R]]++,update(R,1);
    return ans;
}

inline void solve(int k,int dL,int dR,int l,int r)
{
    //cout << dp[k][n] << endl;
    if(dL>dR||l>r) return;
    int mid = (l+r)>>1,d = 0;
    for(int i=dL;i<=dR&&i<mid;i++)
    {
        ll res = calc(i+1,mid);
        if(dp[k][mid]>dp[k-1][i]+res)
        {
            dp[k][mid] = dp[k-1][i] + res;
            d = i;
        }
    }
    solve(k,dL,d,l,mid-1);solve(k,d,dR,mid+1,r);
}

int main()
{
    n = read();k = read();
    memset(dp,127,sizeof(dp));dp[0][0]=0;
    for(re int i=1;i<=n;i++) a[i] = read();
    cnt[a[1]]++;L = 1,R = 1;
    for(re int i=1;i<=k;i++)solve(i,0,n-1,1,n);
    printf("%lld\n",dp[k][n]);
    return 0;
}
posted @ 2020-01-20 09:29  wlzs1432  阅读(174)  评论(0编辑  收藏  举报