• HDU3045 Picnic Cows


    题面

    HDU

    vjudge

    题解

    将权值排序,则分组一定是连续的

    设$f[i]$表示前$i$头牛的最小代价,则($a[i]$为$i$的权值):

    $$ f[i] = f[j - 1] + sum[i] - sum[j - 1] - (i - j + 1) * a[j] $$

    套上斜率优化的板子即可。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x))
    
    const int maxn(5e5 + 10);
    int n, t, q[maxn];
    long long sum[maxn], a[maxn], f[maxn];
    inline long long x(int i) { return a[i]; }
    inline long long y(int i) { return f[i - 1] - sum[i - 1] + (i - 1) * a[i]; }
    
    inline bool check(int i, int j, int k)
    {
    	return (y(i) - y(j)) * (x(j) - x(k)) <= (y(j) - y(k)) * (x(i) - x(j));
    }
    
    int main()
    {
    	while(~scanf("%d%d", &n, &t))
    	{
    		for(RG int i = 1; i <= n; i++) scanf("%lld", a + i);
    		std::sort(a + 1, a + n + 1);
    		for(RG int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
    		int S = t << 1, head = 1, tail = 0;
    		for(RG int i = t; i < S; i++) f[i] = sum[i] - i * a[1];
    		for(RG int i = S; i <= n; i++)
    		{
    			while(head < tail && check(i - t + 1, q[tail], q[tail - 1])) --tail;
    			q[++tail] = i - t + 1;
    			while(head < tail && (y(q[head + 1]) - y(q[head]))
    					<= (x(q[head + 1]) - x(q[head])) * i) ++head;
    			f[i] = f[q[head] - 1] + sum[i] - sum[q[head] - 1] -
    				(i - q[head] + 1) * a[q[head]];
    		}
    		printf("%lld
    ", f[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    链表详解自带代码
    队列
    单词翻转
    表达式求值
    一元多项式
    循环链表
    学生成绩管理系统
    双向循环链表
    双向链表
    静态链表
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10220207.html
Copyright © 2020-2023  润新知