zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 077 E

    https://arc077.contest.atcoder.jp/tasks/arc077_c

    有m个点围成一个圈,按顺时针编号为1到m,一开始可以固定一个位置x,每次操作可以往顺时针方向走一步或直接走到x。现在给出n个位置a[1..n],初始时在a[1],第i次要从a[i]走到a[i+1],在x可以任意选择的情况下使总步数最小。 

    对于从a走到b来说

    若选择的x=a 或 a+1,那么不会使步数减少

    若选择的x=a+2,会使步数减少1

    若选择的x=a+3,会使步数减少2

    ……

    问题就变成了 给区间[l,r]加首项为1,公差为1的等差数列

    给位置l 加1,位置l+1加2,位置l+2加3……位置r加r-l+1

    那么令cnt[l]加1,cnt[r+1]减r-l+1+1,cnt[r+2]减r-l+1

    对cnt做一遍前缀和,得到差分数组

    在做一遍前缀和,可以得到本身的值

    据说这个叫二阶差分

    两遍前缀和后的cnt数组就是把位置选在x,会使原本的步数减少多少

    取最大的一个,总步数减它就是答案

    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    
    #define N 100001 
    
    int a[N];
    long long cnt[N<<1];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    int main()
    {
        int n,m;
        read(n); read(m);
        for(int i=1;i<=n;++i) read(a[i]);
        int l,r;
        long long tot=0;
        for(int i=1;i<n;++i)
        {
            l=a[i];
            r=a[i+1];
            if(l>r) r+=m;
            tot+=r-l;
            if(r-l>1)
            {
                cnt[l+2]++; 
                cnt[r+1]-=r-(l+2)+2;
                cnt[r+2]+=r-(l+2)+1;
            }
        }
        for(int i=1;i<=m*2;++i) cnt[i]+=cnt[i-1];
        for(int i=1;i<=m*2;++i) cnt[i]+=cnt[i-1];
        long long ans=tot;
        for(int i=1;i<=m;++i) ans=min(ans,tot-cnt[i]-cnt[i+m]);
        cout<<ans;
    }
  • 相关阅读:
    Hdu 2389 二分匹配
    Hdu 1156
    Hdu 1255
    Hdu 1542
    python 中初始化二维数组的方法
    chrome扩展小试
    浏览器的重绘与重排
    js执行环境相关
    js 触摸事件
    js柯里化的一个应用
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8612694.html
Copyright © 2011-2022 走看看