发布时间:2025-12-09 12:00:09 浏览次数:2
题目传送门
提供两种做法
正常连边后,对于每个位置 \(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;}设 \(f[i]\) 表示处理 \(i\) 到 \(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 longconst 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;}