zoukankan      html  css  js  c++  java
  • 题解 POJ3709 【K-Anonymous Sequence】

    题目链接:Link

    Problem

    Solution

    题意是给你一个n长度递增数列,将其分组,每组不少于m个,每组的cost是每组中所有元素减去里面最小元素的值的总和,要求你算最小的cost。
    显然可以用dp完成。

    [f(i) = minlimits_{0 le j le i-m } { f(j)+sum limits_{k=j+1}^{i} ( a_k - a_{j+1} ) } ]

    处理后得:

    [f_j - s_j +j * a_{j+1} = i * a_{j+1} + f_i - s_i ]

    分析得:

    • 需要维护下凸壳
    • $ a_{j+1} $ 单调增
    • i 单调增

    故可用单调队列维护。
    注意:决策j是有限制的,须特殊处理。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int maxn=500005;
    int T,n,m,Q[maxn],L,R;
    LL a[maxn],s[maxn],f[maxn],X[maxn],Y[maxn];
    int main()
    {
    	#ifdef local
    	freopen("pro.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T-->0)
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    		for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    		Q[L=R=1]=0;
    		X[0]=1;
    		for(int i=m;i<=2*m-1&&i<=n;i++)
    		{
    			f[i]=s[i]-i*a[1];
    			X[i]=a[i+1];
    			Y[i]=f[i]-s[i]+i*a[i+1];
    		}
    		for(int i=2*m;i<=n;i++)
    		{
    			int p=i-m;
    			while(L<R&&(Y[Q[R]]-Y[Q[R-1]])*(X[p]-X[Q[R-1]])>=(Y[p]-Y[Q[R-1]])*(X[Q[R]]-X[Q[R-1]])) R--;
    			Q[++R]=p;
    			while(L<R&&(Y[Q[L+1]]-Y[Q[L]])<=i*(X[Q[L+1]]-X[Q[L]])) L++;
    			int j=Q[L];
    			f[i]=f[j]+s[i]-s[j]-(i-j)*a[j+1];
    			X[i]=a[i+1];
    			Y[i]=f[i]-s[i]+i*a[i+1];
    		}
    		printf("%lld
    ",f[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Haskell Types与Typeclasses
    Haskell Tuple相关总结
    Haskell List相关操作
    Emacs 常用快捷键
    Emacs 参考资料
    Haskell Platform (windows)
    生成zip压缩包
    递归复制一个文件
    写表格
    读表格
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11629818.html
Copyright © 2011-2022 走看看