题目链接

本蒟蒻的第一篇题解,写得不好请指出,敬请谅解

题意:

有\(n\)头奶牛,分布在一些房间,某些房间可能有多头牛,要让这些牛按顺时针移动,求使每一个房间刚好有一个奶牛的最小花费

花费计算:如果一头奶牛穿过了\(d\)扇门,他消耗的能量为\(d^2\)

分析:

先把这个环看成一条链

首先说一个东西:如果有\(1\)头奶牛在\(a\)点,\(1\)头奶牛在\(b\)点,还有一个没有奶牛的\(c\)点,且\(c>b>a\),要想有一头奶牛在\(b\)点,一头奶牛在\(c\)点,方案\(a \to b,b \to c\)比方案\(a \to c\)好

很容易知道这是对的,可以设\(x=b-a,y=c-b\),而\(c-a=y+x\),所以\((x+y)^2=x^2+y^2+2xy>x^2+y^2\)

也就是说在如果一个房间的奶牛的移动算一个移动过程,移动过程中一头奶牛不要越过另一头没有移动的奶牛

所以可以直接从一个起点开始,如果这个房间里有超过\(1\)头奶牛,就把这些奶牛移到依次后面每一个的房间的末尾,直到没有多余的奶牛可以移动为止

留下房间里最后一头奶牛,就是上一次最后一头牛,每一个房间都这么处理

为了好写代码,可以留下最后一头牛,把这个房间里多余的奶牛移动到下一个房间,下一个房间再做处理

问题是起点如何选择

当一个起点是合法时,\(\sum_{i=1}^{n}c_{i} \geqslant i\)

不知道就枚举呗,反正\(n\)不超过\(1000\)

窝语文不好,只能描述成这样惹

代码:

为每一个奶牛编号,为\(1 \sim n\)

用\(d_i\)来表示编号为\(i\)的奶牛走过的距离

用\(vector\)来存每一个房间里的奶牛

因为\(push\_back\)是把元素\(push\)到末尾,所以留下最后一个,其他的往下一个房间移动(还是上面那个东西)

然后注意下一个房间\(%n\)就行了

#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define reg register int
#define msz(a) memset(a, 0, sizeof a);
#define rep1(i, j, n) for (reg i = j; i <= n; ++i)
#define rep2(i, j, n) for (reg i = j; i >= n; --i)
typedef long long LL;
typedef pair <int, int> PII;
const int INF1 = 0x3f3f3f3f, INF2 = 0x7fffffff;
int n, d[1005], ans, nowid, result = INF2;
vector <int> a[1005], b[1005];
bool vis[1005];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
for (int j = 1; j <= x; ++j) a[i].push_back(++nowid), b[i].push_back(nowid);
}
for (int start = 1; start <= n; ++start) {
bool flg = 1;
for (int now = start; ; ++now) {
if (now > n) now %= n;
if (now == start && flg == 0) break;
if (a[now].empty()) continue;
flg = 0;
int sz = a[now].size();
int p = now + 1;
if (p > n) p %= n;
for (int i = 0; i < sz - 1; ++i) {
a[p].push_back(a[now][i]);
d[a[now][i]]++;
}
int endnum = a[now][sz - 1];
a[now].clear();
a[now].push_back(endnum);
}
for (int i = 1; i <= n; ++i) {
if (a[i].size() != 1) { ans = -1; break; }
ans += d[i] * d[i];
}
if (ans ^ -1) result = min(result, ans);
msz(d); msz(vis); ans = 0;
for (int i = 1; i <= n; ++i) a[i].clear();
for (int i = 1; i <= n; ++i)
for (int j = 0; j < (int)b[i].size(); ++j)
a[i].push_back(b[i][j]);
}
printf("%d", result);
return 0;
}

\(n^2\)算法可以通过\(1000\)的数据,那么\(100000\)的数据怎么办呢

可以发现枚举\(start\)会出现许多没用的枚举,那哪个一个\(start\)可以确保不会出现非法情况呢

可以大概猜出是最密集的那个地方的开头吧

就是说最大字段和

因为全部奶牛的和为\(n\),所以所有\(c_i\)的和一定是最大子段和

所以要把每一个\(c_i\)与\(1\)做差,可以清晰看出最大的字段,再求出最大子段和的起点

证明也很简单:

设最大子段和的值为\(x\),如果最大子段和不合法,那么在最大子段和之后必然有一个字段的值 \(\leqslant -x-1\),由于所有数的和为\(0\),那么在这个字段之后,剩下的那个字段和\(\geqslant 1\)

所以最大子段和的值不为\(x\),矛盾

这个证明有点。。充分显示出我的菜

然后就是环状最大子段和惹

环状最大子段和好像可以用单调队列,但是我用了另一种方法

分两种情况讨论:

\(1\).这个字段没有包含\(c_1\)和\(c_n\),那么就是本来的最大子段和

\(2\).字段包含了\(c_1\)和\(c_n\),那就是整个和减去全部的最小字段和

下面是代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mp make_pair
#define reg register int
#define msz(a) memset(a, 0, sizeof a);
#define rep1(i, j, n) for (reg i = j; i <= n; ++i)
#define rep2(i, j, n) for (reg i = j; i >= n; --i)
typedef long long LL;
typedef pair <int, int> PII;
const int INF1 = 0x3f3f3f3f, INF2 = 0x7fffffff;
const int N = 1e5 + 5;
int n, d[N], ans, nowid, result = INF2, maxn, start, f[N], b[N];
vector <int> a[N];
bool vis[N];
signed main() {
// freopen("P6170_7.in", "r", stdin);
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) {
int x;
scanf("%lld", &x);
b[i] = x - 1;
for (int j = 1; j <= x; ++j) a[i].push_back(++nowid);
}
bool flg = 1;
int m1 = 0, m2 = 0, sum = 0, bg1, st1, st2;
for (int i = 1; i <= n; ++i) {
if (f[i - 1] > 0) f[i] = f[i - 1] + b[i];
else f[i] = b[i], bg1 = i;
if (f[i] > m1) m1 = f[i], st1 = bg1;
sum += b[i];
b[i] = -b[i];
}
for (int i = 1; i <= n; ++i) {
if (f[i - 1] > 0) f[i] = f[i - 1] + b[i];
else f[i] = b[i];
if (f[i] > m2) m2 = f[i], st2 = i + 1;
}
m2 = sum + m2;
if (m1 > m2) start = st1;
else start = st2;
for (int now = start; ; ++now) {
if (now > n) now %= n;
if (now == start && flg == 0) break;
if (a[now].empty()) continue;
flg = 0;
int sz = a[now].size();
int p = now + 1;
if (p > n) p %= n;
for (int i = 0; i < sz - 1; ++i) {
a[p].push_back(a[now][i]);
d[a[now][i]]++;
}
int endnum = a[now][sz - 1];
a[now].clear();
a[now].push_back(endnum);
}
for (int i = 1; i <= n; ++i)
ans += d[i] * d[i];
printf("%lld", ans);
return 0;
}

洛谷 P3137 [USACO16FEB]Circular Barn S的更多相关文章

  1. 洛谷 P3137 [USACO16FEB]圆形谷仓Circular Barn_Silver

    P3137 [USACO16FEB]圆形谷仓Circular Barn_Silver 题目描述 Being a fan of contemporary architecture, Farmer Joh ...

  2. 洛谷P3138 [USACO16FEB]负载平衡Load Balancing_Silver

    P3138 [USACO16FEB]负载平衡Load Balancing_Silver 题目描述 Farmer John's NN cows are each standing at distinct ...

  3. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  4. USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)

    usaco ch1.4 sort(d , d + c, [](int a, int b) -> bool { return a > b; }); 生成与过滤 generator&& ...

  5. 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)

    To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows con ...

  6. 洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…(树规)

    题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...

  7. 洛谷 P3128 [USACO15DEC]最大流Max Flow-树上差分(点权/点覆盖)(模板题)

    因为徐州现场赛的G是树上差分+组合数学,但是比赛的时候没有写出来(自闭),背锅. 会差分数组但是不会树上差分,然后就学了一下. 看了一些东西之后,对树上差分写一点个人的理解: 首先要知道在树上,两点之 ...

  8. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  9. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  10. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

随机推荐

  1. LAL v0.32.0发布,更好的支持纯视频流

    Go语言流媒体开源项目 LAL 今天发布了v0.32.0版本.距离上个版本刚好一个月时间,LAL 依然保持着高效迭代的状态. LAL 项目地址:https://github.com/q19120177 ...

  2. JMX port被占用

    JMX port被占用 解决方案 win+R打开DOS窗口,进入window命令,注意:要以管理员身份打开(快捷键:ctrl+shift+enter): 使用命令:netstat -aon|finds ...

  3. 1759E(方案枚举)

    题目链接 题目大意: 给你n个数(n个宇航员对应的能量值) 一个h ,h表示机器人当前的能量值.机器人拥有2中绿色的药剂,一瓶蓝色的药剂.其中绿色的药剂可以使机器人的能量值变为现在的2倍(2-> ...

  4. IDEA项目下out与target目录的区别详解

    IDEA项目下out与target目录的区别详解 一.目录主要区别: out存放的是该项目下所有Module(模块)的编译结果. target存放的是单个Module的编译结果. 二.目录详解 out ...

  5. 医疗在线OLAP场景下基于Apache Hudi 模式演变的改造与应用

    背景 在 Apache Hudi支持完整的Schema演变的方案中(https://mp.weixin.qq.com/s/rSW864o2YEbHw6oQ4Lsq0Q), 读取方面,只完成了SQL o ...

  6. 【大数据】kafka-02:Kafka Connect内容、原理及使用

    〇.概述 1.常见资料 (1)confluent https://docs.confluent.io/5.4.0/connect/kafka-connect-jdbc/sink-connector/s ...

  7. BFS算法套路框架

    一.概念 1.定义 Broad First Search 2.与DFS区别 BFS找到的路径最短 3.本质 找出图中从起点到终点的最近距离 二.二叉树的最小高度111 1.代码 /** * Defin ...

  8. 【Java SE进阶】Day11 网络编程、TCP应用程序

    一.网络编程入门 1.软件架构 C/S:QQ.迅雷 B/S 共同点:都离不开网络的支持 网络编程:在一定的协议下,实现两台计算机通信 2.网络通信协议 通信协议:需遵守的规则,只有遵守才能通信 主要包 ...

  9. 【大数据面试】【数仓项目】分层:ODS层、DWD层、DWS层、ADS层构成、操作

    一.ODS层 1.保持数据原貌,不做任何修改 2.数据压缩:LZO压缩,减少磁盘空间 3.创建的是分区表:可以防止后续的全表扫描 包括 用户行为:string line dt    ods_start ...

  10. (数据科学学习手札148)geopandas直接支持gdb文件写出与追加

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,在我之前的某篇文章中为大家介绍 ...