1. 程式人生 > >【JZOJ A組】輕功(qinggong)

【JZOJ A組】輕功(qinggong)

Description

題目背景:
尊者神高達進入了基三的世界,作為一個 mmorpg 做任務是必不可少的,然而跑地圖卻令人十分不爽。好在基三可以使用輕功,但是尊者神高達有些手殘,他決定用梅花樁練習輕功。
題目描述:
一共有 n 個木樁,要求從起點(0)開始,經過所有梅花樁,恰好到達終點 n,尊者神高達一共會 k 種門派的輕功,不同門派的輕功經過的梅花樁數不同,花費時間也不同。但是尊者神高達一次只能使用一種輕功,當他使用別的門派的輕功時,需要花費 W 秒切換(開始時可以是任意門派,不需要更換時間)。由於尊者神高達手殘,所以經過某些梅花樁(包括起點和終點)時他不能使用一些門派的輕功。尊者神高達想知道他最快多久能到達終點如果無解則輸出-1。

Input

第一行 n,k,W
接下來 k 行,每行為 ai 和 wi 代表第 i 種輕功花費 vi 秒經過 ai 個木樁。
接下來一行 Q 為限制條件數量。
接下來 Q 行,每行為 xi 和 ki 代表第 xi 個梅花樁不能使用第 ki 種門派的輕功經過。

Output

一行答案即所需最短時間。

Sample Input

Sample Input1:
6 2 5
1 1
3 10
2
1 1
2 1

Sample Input2:
6 2 5
1 1
3 10
0

Sample Output

Sample Output1:
18

樣例解釋 1:

先用第二種輕功花費 10 秒到 3,再用 5 秒切換到第一種輕功,最後再用 3 秒時間到 6.一共花費 10+5+3=18 秒

Sample Output2:
6

樣例解釋 2:

直接花費 6 秒到 6;

Data Constraint

20%的資料 n<=20,k<=10,Q<=200;
對於另外 20%的資料 W=0
對於另外 20%的資料 Q=0
所以資料滿足 n<=500,k<=100,Q<=50000,vi<=1e7;
保證資料合法

Hint

Q:請問第一題可不可以往回跳
A:不可以

思路

一個DP題

設f[i][j]為從0到i,使用的最後一種輕功為j的最小代價
判斷:記錄字首和,若a[j][y]-a[j][x]==0則可以通過
這樣O(nk2)能過
其實還可以用單調佇列優化一下

程式碼

#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,m,w,q,b[177][577],f[577][177];
ll min(ll x,ll y)
{
	return x<y?x:y;
}
struct A
{
	ll v,t;
}a[177];
int main()

//	freopen("qinggong.in","r",stdin);freopen("qinggong.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&w);
	for(ll i=1; i<=m; i++)
	{
		scanf("%lld%lld",&a[i].v,&a[i].t);
	}
	scanf("%lld",&q);
	for(ll i=1; i<=q; i++)
	{
		ll x,y;
		scanf("%lld%lld",&x,&y);
		b[y][x]=1;
	}
	for(ll i=1; i<=m; i++)
	{
		for(ll j=1; j<=n; j++) b[i][j]+=b[i][j-1];
	}
	memset(f,0x3f,sizeof(f));
	for(ll i=1; i<=m; i++)
	{
		if(b[i][a[i].v]==0) f[a[i].v][i]=min(f[a[i].v][i],a[i].t);
	}
	for(ll i=0; i<=n-1; i++)
	{
		for(ll x=1; x<=m; x++)
		{
			for(ll y=1; y<=m; y++)
			{
					ll j=i+a[y].v;
					if(j>n||b[y][j]-b[y][i]) continue;
					if(x==y) f[j][y]=min(f[j][y],f[i][x]+a[y].t);
					else f[j][y]=min(f[j][y],f[i][x]+a[y].t+w);
			}
		}
	}
	ll ans=inf;
	for(ll i=1; i<=m; i++) ans=min(ans,f[n][i]);
	if(ans==inf) printf("-1");else printf("%lld",ans);
}