题目传送门

提供两种做法

1.Dijstra最短路

正常连边后,对于每个位置 \(i\) 都加上 \(i-1->i\)\(i->i+1\) ,长度为 \(1\) 的边,相当于先按照原方法走再改动。

不过题目中要求改动后的数必须是自然数(也就是正整数),所以不是所有点都可以加,必须逐个判断能否改动。

然后跑一个堆优化Dijkstra即可。

$Code\ by\ $ @wsy_jim

%%%

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int INF=0x3f3f3f3f,N=1000010;

int e[4*N],ne[4*N],idx,h[N],w[4*N],n,ls[N],rs[N];

inline int read(){
    int x=0,y=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*y;
}

void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

namespace dijkstra{
    int dist[N];
    bool vis[N];
    int dijkstra(int st,int ed){
        memset(dist,0x3f,sizeof dist);
        priority_queue<pii,vector<pii>,greater<pii> > q;
        dist[st]=0;
        q.push(make_pair(0,st));
        while(q.size()){
            pii op=q.top();
            q.pop();
            int dis=op.first,ver=op.second;
            if(vis[ver]) continue;
            vis[ver]=1;
            for(int i=h[ver];~i;i=ne[i]){
                int j=e[i];
                if(dist[j]>dist[ver]+w[i]){
                    dist[j]=dist[ver]+w[i];
                    q.push(make_pair(dist[j],j));
                } 
            }
        }
        if(dist[ed]==0x3f) return -1;
        return dist[ed];
    }
}

int main(){

    memset(h,-1,sizeof h);

    n=read();
    for(int i=1,k;i<=n;i++){
        k=read();
        if(i+k<=n) add(i,i+k+1,0);
        else add(i,n+1,i+k-n);
        for(int j=i+1;j<=i+k+1&&j<=n&&!ls[j];j++)	ls[j]=1,add(j,j-1,1);
		for(int j=i+k+1;j<=n&&!rs[j];j++)	rs[j]=1,add(j,j+1,1);
    }

    // for(int i=1;i<=n;i++){
    //     for(int j=h[i];~j;j=ne[j]) printf("%d %d  ",e[j],w[j]);
    //     printf("\n");
    // }

    ll ans=dijkstra::dijkstra(1,n+1);

    printf("%lld\n",ans);
    
    return 0;
}

2.树状数组维护DP

\(f[i]\) 表示处理 \(i\)\(n\) 的最优答案。
易得

\[f[i] = min ( f[j] + abs(j - i - 1 - a[i]) )\ \ \ (i<j<n) \]

把这个式子打开

\[f[i] = min(f[j]+j)-(i+1+a[i]) (j ≥ a[i]+i+1) \]

\[f[i] = min(f[j]-j)+(i+1+a[i]) (j<a[i]+i+1) \]

然后用树状数组维护 \(f[j]+j\)\(f[j]-j\) 即可

\(Code\)

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#include<chrono>
#include<random>
#include<unordered_map>
using namespace std;

#define ll long long
#define ull unsigned long long
#define rll register long long
#define ri register int
#define il inline
//#define int long long

const int INF=0x3f3f3f3f,N=1e6+10;
int n,t;
int ins[N];
int f[N];
int t1[N],t2[N];

il ll read(){
    ll x=0,y=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
            y=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*y;
}

il int lowbit(int x){
    return x&(-x);
}

il int query1(int x){
    int mid=INF;
    x=(n+1)-x;
    if(x>n||x<=0)
        return mid;
    while(x){
        mid=min(mid,t1[x]);
        x-=lowbit(x);
    }
    return mid;
}

il int query2(int x){
    int mid=INF;
    if(x>n||x<=0)
        return mid;
    while(x){
        mid=min(mid,t1[x]);
        x-=lowbit(x);
    }
    return mid;
}

il void wh(int x){
    int mid=x;
    while(mid<=n){
        t2[mid]=min(t2[mid],f[x]-x);
        mid+=lowbit(mid);
    }
    mid=(n+1)-x;
    while(mid<=n){
        t1[mid]=min(t1[mid],f[x]+x);
        mid+=lowbit(mid);
    }
}


signed main(){
    n=read();
    memset(t1,0x3f,sizeof(t1));
    for(ri i=1;i<=n;i++)
        ins[i]=read();
    for(ri i=n;i>=1;i--){
        f[i]=abs(n-i-ins[i]);
        t=ins[i]+i+1;
        if(t<n)
            f[i]=min(f[i],query1(t)-t);
        f[i]=min(f[i],query2(t)+t);
        wh(i);
    }
    printf("%d",f[1]);
    return 0;
}