BZOJ2259 [Oibh]新型计算机 题解
提供两种做法
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;
}