1 条题解
-
0
自动搬运
来自洛谷,原作者为

sbno333
不进北省不改签!!!搬运于
2025-08-24 22:14:55,当前版本为作者最后更新于2023-07-23 15:36:16,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
其实这道题比较水,
果然是远古时期的题我们假设每一名同学都向一个方向移动,此时距离确定,我们发现,如果考虑两个方向,比如有 名同学,一个座位到任意座位最近距离有可能有以下情况:距离 方向 某个格子向左和向右均为此数,只有一个 向右 向左 向右 向左 无 为 时:
距离 方向 向右 向左 向右 向左 向右 向左 无 而当我们指定方向时,就有距离为 到 中的一种,我们发现 是临界点,如果值大于它,实际距离就会减小。
当 时:
特定方向距离 实际距离 当 时:
特定方向距离 实际距离 不难发现我们可以将座位号进行转圈,比如 。
此时特定距离将同时加或减一个数,超界就循环,比如 ,。
但不管怎样,都是离 $\lfloor \frac{n}{2} \rfloor,\lceil \frac{n}{2} \rceil$ 越远越好。
然而,对应 , 的特定方向距离,于是我们就用没有对应特定方向距离的同学来对应,而周围的座位也对应,因此我们要求所有特定距离中最长连续的没有同学满足的长度。
由于转座位时,距离会循环,因此我们要特判两边的连续无同学对应的和。
我们再分成偶数和奇数两种情况,进行判断距离。
当然这样你以为就对了么?
不!你会获得 分的好成绩
作者我第一次提交的成绩,调试了好几遍,因为题目中有这句话:需要注意的是 $p_1$ 可以坐在 $p_n$ 左边也可以坐在 $p_n$ 右边。因此我们要把 数组倒过来算一遍,输出最小值。
#include<bits/stdc++.h> using namespace std; bool t[1000009]; int a[1000009]; int main(){ int n; int ma; int u; int x,y; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } memset(t,0,sizeof(t)); for(int i=1;i<=n;i++){//特定方向距离记录 t[(a[i]-i+n)%n]=1; } ma=0; u=0; for(int i=0;i<n;i++){//算最长连续无同学对应座位 if(t[i]){ ma=max(ma,u); u=0; }else{ u++; } } ma=max(ma,u); u=0; for(int i=0;i<n;i++){//特判循环 if(!t[i]){ u++; }else{ break; } } for(int i=n-1;i>=0;i--){ if(!t[i]){ u++; }else{ break; } } ma=max(ma,u); x=n/2; if(n%2){//分奇偶情况 x-=ma/2; }else{ if(ma>0){ x--; ma--; } x-=ma/2; } memset(t,0,sizeof(t));//倒过来算 for(int i=1;i<=n;i++){ t[(a[n+1-i]-i+n)%n]=1; } ma=0; u=0; for(int i=0;i<n;i++){ if(t[i]){ ma=max(ma,u); u=0; }else{ u++; } } ma=max(ma,u); u=0; for(int i=0;i<n;i++){ if(!t[i]){ u++; }else{ break; } } for(int i=n-1;i>=0;i--){ if(!t[i]){ u++; }else{ break; } } ma=max(ma,u); y=n/2; if(n%2){ y-=ma/2; }else{ if(ma>0){ y--; ma--; } y-=ma/2; } cout<<min(x,y); return 0; }不难发现这是贪心
作者我写到几乎末尾才发现思路的话我思路不是特别清晰,所以写的特别啰嗦,所以大家主要看代码,思路仅供参考,帮助大家理解,祝大家切题愉快。
- 1
信息
- ID
- 4852
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者