1. 程式人生 > >【BZOJ2259】[Oibh]新型計算機 最短路

【BZOJ2259】[Oibh]新型計算機 最短路

進行 mes string ont mda const 文件 queue 個數

【BZOJ2259】[Oibh]新型計算機

Description

Tim正在擺弄著他設計的“計算機”,他認為這臺計算機原理很獨特,因此利用它可以解決許多難題。
但是,有一個難題他卻解決不了,是這臺計算機的輸入問題。新型計算機的輸入也很獨特,假設輸入序列中有一些數字(都是自然數——自然數包括0),計算機先讀取第一個數字S1,然後順序向後讀入S1個數字。接著再讀一個數字S2,順序向後讀入S2個數字……依此類推。不過只有計算機正好將輸入序列中的數字讀完,它才能正確處理數據,否則計算機就會進行自毀性操作!
Tim現在有一串輸入序列。但可能不是合法的,也就是可能會對計算機造成破壞。於是他想對序列中的每一個數字做一些更改,加上一個數或者減去一個數,當然,仍然保持其為自然數。使得更改後的序列為一個新型計算機可以接受的合法序列。

不過Tim還希望更改的總代價最小,所謂總代價,就是對序列中每一個數操作的參數的絕對值之和。
寫一個程序:
? 從文件中讀入原始的輸入序列;
? 計算將輸入序列改變為合法序列需要的最小代價;
? 向輸出文件打印結果。

Input

輸入文件包含兩行,第一行一個正整數N,N<1 000 001。
輸入文件第二行包含N個自然數,表示輸入序列。

Output

僅一個整數,表示把輸入序列改變為合法序列需要的最小代價,保證最小代價小於109。

Sample Input

4
2 2 2 2

Sample Output

1

題解:一開始以為是DP+樹狀數組,後來發現竟然是最短路~

從i向i+s1+1連一條邊權為0的邊,在從i+s1+1向兩邊連邊權為1的邊,註意不要重復連邊,修改後的s1不能是負數

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <utility>
#define mp(A,B)	make_pair(A,B)
using namespace std;
const int maxn=1000010;
priority_queue<pair<int,int> > pq;
int dis[maxn],lv[maxn],rv[maxn],to[maxn<<2],next[maxn<<2],head[maxn],val[maxn<<2],vis[maxn];
int n,m,cnt;
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
	scanf("%d",&n);
	int i,j,u;
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)
	{
		scanf("%d",&u);
		if(i+u>n)	add(i,n+1,i+u-n);
		else	add(i,i+u+1,0);
		for(j=i+1;j<=i+u+1&&j<=n&&!lv[j];j++)	lv[j]=1,add(j,j-1,1);
		for(j=i+u+1;j<=n&&!rv[j];j++)	rv[j]=1,add(j,j+1,1);
	}
	memset(dis,0x3f,sizeof(dis));
	pq.push(mp(0,1)),dis[1]=0;
	while(!pq.empty())
	{
		u=pq.top().second,pq.pop();
		if(vis[u])	continue;
		vis[u]=1;
		for(i=head[u];i!=-1;i=next[i])
			if(dis[to[i]]>dis[u]+val[i])
				dis[to[i]]=dis[u]+val[i],pq.push(mp(-dis[to[i]],to[i]));
	}
	printf("%d",dis[n+1]);
	return 0;
}

【BZOJ2259】[Oibh]新型計算機 最短路