【贪心】[USACO2016 金组]Circular Barn

解决农场主John的问题:如何让牛从初始位置移动到每个房间恰好有一头牛的状态,使得总的移动能耗最小。采用贪心策略,通过队列记录牛的位置,并计算总能耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Being a fan of contemporary architecture, Farmer John has built a new barn in the shape of a perfect circle. Inside, the barn consists of a ring of nn rooms, numbered clockwise from 1…n1…n around the perimeter of the barn (3≤n≤100,0003≤n≤100,000). Each room has doors to its two neighboring rooms, and also a door opening to the exterior of the barn.
Farmer John owns nn cows, and he wants exactly one cow to end up in each room in the barn. However, the cows, being slightly confused, line up at haphazard doors, with possibly multiple cows lining up at the same door. Precisely cici cows line up outside the door to room ii, so ∑ci=n∑ci=n.

To manage the process of herding the cows so that one cow ends up in each room, Farmer John wants to use the following approach: each cow enters at the door at which she initially lined up, then walks clockwise through the rooms until she reaches a suitable destination. Given that a cow walking through dd doors consumes d2d2 energy, please determine the minimum amount of energy needed to distribute the cows so one ends up in each room.

INPUT FORMAT (file cbarn.in):

The first line of input contains nn. Each of the remaining nn lines contain c1…cnc1…cn.

OUTPUT FORMAT (file cbarn.out):

Please write out the minimum amount of energy consumed by the cows.

SAMPLE INPUT:

10
1
0
0
2
0
0
1
2
2
2

SAMPLE OUTPUT:

33
题目大意,给定一个环长为n的环上每个点上有ai只牛,每只牛可以在环上顺时针移动,代价为移动距离的平方,问将环上每个节点上都有一只牛的代价是多少

题目解析

可以发现我们如果需要移动ij(j>i)到达kp(p>k)的话我们有i>k同时j>p那么我们就有对于任意的j=k同样满足,那么我们贪心处理一下,对于每一次循环到当前位置,如果我们有当前位置有可以出发的奶牛那么一定出发(更优)然后扔下一只队列中距离最远的,没有就扔下一只继续走。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 100000;
int a[MAXN+10], c[MAXN+10];
char ch;
void Read(int &s){
    while((ch=getchar()),ch<'0'||ch>'9');
    s = ch-'0';
    while((ch=getchar()),ch>='0'&&ch<='9')
        s = s*10+ch-'0';
    ungetc(ch, stdin);
}
int main(){
    int n;
    Read(n);
    for(int i=1;i<=n;i++){
        Read(c[i]);
        a[i] = i;
    }
    queue<int> que;
    long long ans = 0;
    for(int i=1;i<=n;i++){
        if(!que.empty()){
            int u = que.front();
            que.pop();
            ans += 1LL*(i-u)*(i-u);
            a[i] = u;
            c[i] ++;
        }
        for(;c[i]>1;c[i]--) que.push(i);
    }
    int tn = n*2;
    for(int i=n+1;i<=tn;i++){
        if(!que.empty()){
            if(c[i-n]){
                que.push(a[i-n]+n);
                ans -= 1LL*(i-n-a[i-n])*(i-n-a[i-n]);
            }
            int u = que.front();
            que.pop();
            ans += 1LL*(i-u)*(i-u);
        }
    }
    printf("%lld\n", ans);

    return 0;
}

转载于:https://www.cnblogs.com/JeremyGJY/p/5921598.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值