健美猫

来源:互联网 发布:计算机仿真 知乎 编辑:程序博客网 时间:2024/04/28 04:02

题目大意

旋转序列s使得ni=1|sii|最小

做法

大致思路是可以拆绝对值记录个数即贡献,顺着扫,对于一个位置有两个位置很关键。
(我都不知道我在说什么

#include<cstdio>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=2000000+10;int s[maxn],h[maxn],go[maxn],nxt[maxn];bool bz[maxn];//0 + 1 -int i,j,k,l,t,n,m,tot,cnt;ll num,sum,ans;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void add(int x,int y){    go[++tot]=y;    nxt[tot]=h[x];    h[x]=tot;}int main(){    n=read();    fo(i,1,n){        s[i]=read();        if (s[i]>1){            if (s[i]<=i) add(i-s[i]+1,i);            else add(n-s[i]+i+1,i);        }        if (i+1>s[i]) num-=(ll)s[i],num+=(ll)(i+1),cnt--,bz[i]=1;        else num+=(ll)s[i],num-=(ll)(i+1),cnt++,bz[i]=0;    }    ans=100000000000000;    fo(i,1,n){        num+=(ll)cnt;        ans=min(ans,num);        num-=(ll)abs(s[i]-1);        num+=(ll)abs(s[i]-(n+1));        if (bz[i]) cnt++;else cnt--;        cnt--;        bz[i]=1;        t=h[i];        while (t){            k=go[t];            cnt++;            cnt++;            bz[k]=0;            t=nxt[t];        }    }    printf("%lld\n",ans);}