• [CF868F] Yet Another Minimization Problem


    Description

    给定一个序列,要把它分成k个子序列。每个子序列的费用是其中相同元素的对数。求所有子序列的费用之和的最小值。

    Solution

    仍然是决策单调性的题目。

    (f[i][j])表示把前(i)个数分成(j)份的最小费用。

    [f[i][j]=min(f[k][j-1]+w(k+1,i)) ]

    显然这个决策点是会单调递减的,但是我们不能直接维护一个栈来完成了,因为(w(k+1,i))是不能直接的算的。我们采用分治的做法,先找到(f[mid][j])的决策点,然后分别算([l,mid))((mid,r])的就行了。

    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 100005
    ll f[2][MN],a[MN],w[MN];
    void solve(ll *F,ll *G,int l,int r,int ql,int qr,ll now)
    {
        if(l>r) return;
        register int i,k=0,mid=(l+r)>>1,p=min(mid,qr);
        
        for(i=l;i<=mid;++i) now+=w[a[i]]++;
        for(i=ql;i<=p;++i) now-=--w[a[i]],F[mid]>G[i]+now?F[mid]=G[i]+now,k=i:0;
        for(i=ql;i<=p;++i) now+=w[a[i]]++;
        for(i=l;i<=mid;++i) now-=--w[a[i]];
        solve(F,G,l,mid-1,ql,k,now);
        
        for(i=l;i<=mid;++i) now+=w[a[i]]++;
        for(i=ql;i<k;++i) now-=--w[a[i]];
        solve(F,G,mid+1,r,k,qr,now);
        
        for(i=ql;i<k;++i) ++w[a[i]];
        for(i=l;i<=mid;++i) --w[a[i]];
    }
    int main()
    {
    	register int n=read(),k=read(),i;
    	for(i=1;i<=n;++i) a[i]=read();
    	for(i=1;i<=n;++i) f[1][i]=f[1][i-1]+w[a[i]]++;
    	memset(w,0,sizeof w);
    	for(i=2;i<=k;++i)
    	{
    		memset(f[i&1],0x3f,sizeof f[i&1]);
    		solve(f[i&1],f[(i-1)&1],1,n,1,n,0);
    	}
        printf("%lld
    ",f[k&1][n]);
        return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    iOS 列表三级展开
    iOS 聊天界面
    iOS 地图(添加大头针)
    iOS 地图
    swift 快速创建一些基本控件
    swift
    swift
    swift4.2 打印所有系统字体
    Xcode 去掉控制台无用打印信息
    swift
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10241972.html
Copyright © 2020-2023  润新知