ARC 077 E guruguru - 差分

题目大意:走n-1步每次从a_i走到a_{i+1},每次位置+1(循环意义下)或者位置=x。求最小的x使得步数之和最小。1e5。
题解:显然直接维护a[i]为x取i时能够节省的答案,相当于是等差数列加法,差分差分然后前缀和前缀和即可。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=100010;lint a[N],b[N],c[N];int p[N];
inline int upd(int s,int t,int v) { int L=t-s;return c[s]+=v,c[s+1]+=1-v,c[t+1]-=v+L+1,c[t+2]+=v+L,0; }
int main()
{
//  freopen("data.in","r",stdin);
    int m=inn(),n=inn();lint tot=0,ans=0;rep(i,1,m) p[i]=inn();
    rep(i,1,m-1)
    {
        int s=p[i],t=p[i+1];if(s==t) continue;
        if(t==s+1||(s==n&&t==1)) { tot++;continue; }
        if(s<t) upd(s+1,t,0),tot+=t-s;
        else (s<n?upd(s+1,n,0):0),upd(1,t,n-s),tot+=t+n-s;
    }
    rep(i,1,n) b[i]=b[i-1]+c[i],a[i]=a[i-1]+b[i];
    rep(i,1,n) ans=max(ans,a[i]);
    return !printf("%lld\n",tot-ans);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83346055