Arc077_E Guruguru
2024-09-27 22:03:46
题目大意
有$m$个点编号从小到大按照顺时针编成了一个环,有一枚棋子,每次移动可以选择顺时针移动到下一个或者直接移动到编号为$x$的点,现在有$n-1$次数操作,第$i$次要把棋子从第$A_i$移到第$A_{i+1}$号节点,可以在初始时自由设定$x$,求每次操作移动步数之和的最小值。
题解
$x$对一次移动有意义当且仅当$x$被直接操作经过不在起点上,其中贡献为$起点到终点的距离$+1$-$x$到终点的距离$。
考虑设$x$能减少多少代价,维护$x$取每一个位置时能使总代价减少多少,对于一段操作区间,当$x=l+1,x=l+2...x=r$的差异恰好是一段等差数列,首相为$0$,公差为$1$,可以使用二次差分解决,最后只需要枚举每一个位置记答案最值即可。
复杂度$O(n+m)$。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
using namespace std;
namespace IO{
const int BS=(1<<21)+3; LL Top=0; char Buffer[BS],*HD,*TL,SS[20];
char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
int read(){
int nm=0; char cw=Getchar(); for(;!isdigit(cw);cw=Getchar());
for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0'); return nm;
}
} using namespace IO;
int n,m,dt[M]; LL tot,s[M],ans;
int main(){
n=read(),m=read();
for(register int last=read(),i=1,x;i<n;last=x,i++){
x=read(),dt[last+2]++;
if(last<x) dt[x+1]--,tot+=x-last,s[x+1]-=x-last-1;
else tot+=x+m-last,dt[1]++,dt[x+1]--,s[1]+=m-last-1,s[x+1]-=m+x-last-1;
} ans=tot;
for(register int i=1;i<=m;i++) dt[i]+=dt[i-1],s[i]+=s[i-1]+dt[i],ans=min(ans,tot-s[i]);
printf("%lld\n",ans); return 0;
}
最新文章
- FlashBuilder项目环境配置
- Redis设计与实现读书笔记(一) SDS
- ASCII和16进制对照表
- C语言 &#183; 前缀表达式
- 分享一个绿色版本 sql server 查询器,
- NSFileManager 遍历目录
- NSDictionary读取数据类型异常问题.
- BJOI2015 Day3
- cookie存储记录
- cf div2 239 D
- des加密解密源码 C# key值问题
- RPM安装包-Spec文件參数具体解释与演示样例分析
- IE6/IE7浏览器中";float: right";自动换行的解决方法
- 【Objective-C学习笔记】变量和基本的数据类型
- 京东iPad新品开售销量环比增22倍
- Java 平时作业四
- C#中的yield return用法演示源码
- RCNN 目标识别基本原理
- Trusted Cloud Summit(2018.08.14)
- spring配置多个事务管理器