jzoj 5907.【NOIP2018模擬10.16】輕功
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;
分析: 很顯然的dp啦。 設為到這根木樁,當前氣功為的最小代價。 顯然如果中間都沒有限制的話,那麼有 然後找到中時間花費最小的一個型別,看看切成其他型別是否更優。 判斷中間有沒有限制可以跑字首和。 複雜度是的。
程式碼:
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=507;
const LL inf=1e17;
using namespace std;
int n,m,q,x,y,sum[maxn][maxn],len[maxn],t[maxn];
LL w,f[maxn][maxn];
bool check(int l,int r,int k)
{
LL num=sum[r][k];
if (l) num-=sum[l-1][k];
return (num==0);
}
int main()
{
freopen("qinggong.in","r",stdin);
freopen("qinggong.out","w",stdout);
scanf("%d%d%lld",&n,&m,&w);
for (int i=1;i<=m;i++) scanf("%d%d",&len[i],&t[i]);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
sum[x][y]++;
}
for (int j=1;j<=m;j++)
{
for (int i=1;i<=n;i++) sum[i][j]+=sum[i-1][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) f[i][j]=inf;
}
LL minn;
for (int i=1;i<=n;i++)
{
minn=inf;
for (int j=1;j<=m;j++)
{
if (i-len[j]>=0)
{
if (check(i-len[j],i,j))
{
f[i][j]=min(f[i][j],f[i-len[j]][j]+t[j]);
}
}
minn=min(f[i][j],minn);
}
for (int j=1;j<=m;j++) f[i][j]=min(f[i][j],minn+w);
}
if (minn==inf) printf("-1");
else printf("%lld",minn);
}