Description:
Tim 正在摆弄着他设计的“计算机”,他认为这台计算机原理很独特,因此利用它可以解决许多难题。
但是,有一个难题他却解决不了,是这台计算机的输入问题。新型计算机的输入也很独特,假设输入序列中有一些数字(都是自然数 —— 自然数包括0),计算机先读取第一个数字 $S1$ ,然后顺序向后读入 $S1$ 个数字。接着再读一个数字 $S2$ ,顺序向后读 入 $S2$ 个数字 …… 依此类推。不过只有计算机正好将输入序列中的数字读完,它才能正确处理数据,否则计算机就会进行自毁性 操作!
Tim 现在有一串输入序列。但可能不是合法的,也就是可能会对计算机造成破坏。于是他想对序列中的每一个数字做一些更改,加上一个数或者减去一个数,当然,仍然保持其为自然数。使得更改后的序列为一个新型计算机可以接受的合法序列。
不过 Tim 还希望更改的总代价最小,所谓总代价,就是对序列中每一个数操作的参数的绝对值之和。
写一个程序:
从文件中读入原始的输入序列; 计算将输入序列改变为合法序列需要的最小代价;
向输出文件打印结果。
输入文件包含两行,第一行一个正整数 $N$ , $N<1e^6+1$ 。
输入文件第二行包含 $4$ 个自然数,表示输入序列。
Output
仅一个整数,表示把输入序列改变为合法序列需要的最小代价,保证最小代价小于 $1e^9$ 。
4
2 2 2 2
Sample Output
1
Solution:
这道题居然是个图论最短路。
以修改的代价为边权建图,显然 $$ 的边权为0。
当 $i+a_i+1>n+1$ 时 $$ 的边权为 $a_i+i-n$ 。
同时可以将 $$ 和 $$ 的边权为1。
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; const int inf=0x7fffffff; struct edge{ int u,v,w,nxt; }e[maxn<<2]; int cnt,h[maxn<<1]; void add(int u,int v,int w){ e[++cnt]=(edge){u,v,w,h[u]}; h[u]=cnt; } int n,a[maxn],dis[maxn]; struct node{ int v,w; friend bool operator <(const node &a,const node &b){ return a.w>b.w; } }; priority_queue<node> q; void dijstra(int be){ for(int i=1;i<maxn;i++) dis[i]=inf; dis[be]=0; q.push((node){be,0}); while(!q.empty()){ int u=q.top().v,dist=q.top().w;q.pop(); if(dist!=dis[u]) continue; for(int i=h[u];i;i=e[i].nxt){ int v=e[i].v; if(dis[v]>dis[u]+e[i].w){ dis[v]=dis[u]+e[i].w; q.push((node){v,dis[v]}); } } } } int main(){ freopen("test.in","r",stdin); freopen("test.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int minn=inf; for(int i=1;i<=n;i++){ minn=min(minn,i+a[i]+1); if(i+a[i]<=n) add(i,i+a[i]+1,0); else add(i,n+1,i+a[i]-n); } for(int i=minn;i<=n;i++) add(i,i+1,1); for(int i=1;i<=n;i++) add(i+1,i,1); dijstra(1); printf("%d\n",dis[n+1]); return 0; }
|