10.18NOIP2018模拟赛

T1 轻功

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,用f[i][j]表示走到第i个桩,用第j种轻功的最小值。用一个数组c[i][j]处理出桩和功法之间的关系,1表示不能走,0表示能走。

#include<cstdio> 
#include<iostream> 
#include<algorithm> 
#include<cstring> 
using namespace std; 

typedef long long LL;
const int N=1005; 
LL ans,n,k,W,a[N],w[N],q,x,p; 
LL h[N][N],f[N][N]; 

int main()
{ 
	scanf("%lld%lld%lld",&n,&k,&W); 
	for (LL i=1;i<=k;i++) 
		scanf("%lld%lld",&a[i],&w[i]); 
	scanf("%lld",&q); 
	for (LL i=1;i<=q;i++) 
	{ 
		scanf("%lld%lld",&x,&p); 
		h[x][p]=1; 
		for (LL j=1;j<=a[p];j++) 
			h[x+j][p]=1; 
	} 
	memset(f,31,sizeof(f)); 
	for (LL i=1;i<=k;i++) 
		f[0][i]=0; 
	for (LL i=1;i<=n;i++) 
		for (LL j=1;j<=k;j++) 
			if (!h[i][j])
			{ 
				for (LL ii=1;ii<=k;ii++) 
					if (ii==j&&i-a[j]>=0) f[i][j]=min(f[i][j],f[i-a[j]][ii]+w[j]); 
					else if (i-a[j]>=0) f[i][j]=min(f[i][j],f[i-a[j]][ii]+w[j]+W);	
			} 
	ans = 12345678900; 
	for (LL i = 1;i<=k;i++) 
	ans=min(ans,f[n][i]); 
	if (ans==12345678900) printf("-1"); 
	else printf("%lld",ans); 
} 

T2 开荒

分析

这道题涉及到了一个虚树:1.对于一棵树,我们只保留有用的节点,重新建一棵树,这棵树就叫虚树。2.具体实现:求出所有点的dfs序,按大小排列,用一个栈维护。
但是这道题我还没写出来,大概明天改出来吧。。。。。

posted @ 2018-10-18 23:29  Stooge  阅读(161)  评论(0编辑  收藏  举报