hiho一下 第145周

版权声明:本文为博主原创文章,未经博主允许可以随便转载。 https://blog.csdn.net/liyuanshuo_nuc/article/details/70059816

题目1 : 智力竞赛

时间限制: 5000ms
单点时限: 1000ms
内存限制: 256MB

描述

小Hi、小Ho还有被小Hi强拉来的小Z,准备组队参加一个智力竞赛。竞赛采用过关制,共计N个关卡。在第i个关卡中,小Hi他们需要获得Ai点分数才能够进入下一关。每一关的分数都是独立计算的,即使在一关当中获得超过需要的分数,也不会对后面的关卡产生影响。

小Hi他们可以通过答题获得分数。答对一道题获得S点分数,答错一道题获得T点分数。在所有的N个关卡中,小Hi他们一共有M次答题机会。在每个关卡中,都可以在累计答题次数不超过M的情况下使用任意次的答题机会。

那么现在问题来了,对于给定的N、M、S、T和A,小Hi他们至少需要答对多少道题目才能够完成所有的关卡呢?

输入

每个输入文件包含多组测试数据,在每个输入文件的第一行为一个整数Q,表示测试数据的组数。

每组测试数据的第一行为四个正整数N、M、S和T,意义如前文所述。

第二行为N个正整数,分别表示A1~AN

对于40%的数据,满足1<=N,M<=100

对于100%的数据,满足1<=N,M<=1000,1<=T<S<=10,1<=Ai<=50

对于100%的数据,满足1<=Q<=100

输出

对于每组测试数据,如果小Hi他们能够顺利完成关卡,则输出一个整数Ans,表示小Hi他们至少需要答对的题目数量,否则输出No。

样例输入
1
2 10 9 1
12 35 
样例输出

5

《智力竞赛》题目分析

首先我们可以发现,由于每一关需要的分数Ai是固定的,所以如果确定第i关答错了x题,那么最少需要答对的题目数就是max{0, ⌈(Ai-xT)/S}⌉。

为了描述方便我们把这个值记为c[i][x], 即第i关如果答错的题目数是x,那么这一关最少答对的题目数是c[i][x]

于是这道题实际是让我们决策每一关答错多少题,才能使得在总答题次数不超过M的情况下,总答对的题目数最少。

这是一个比较典型的动态规划题目,比较容易想到可以令f[i][j]表示完成前i关如果总答错题目数是j次,最少需要的总答对题目数。

按关卡划分阶段,每次转移就是枚举第i关答错的题目数x,即

f[i][j] = min{f[i-1][j-x] + c[i][x], | x = 0 .. ⌈Ai/T⌉}

最后我们要在所有f[n][j],j=0..M中找到最小的j满足f[n][j] + j <= M。

这个算法总状态数是O(NM)的,转移复杂度是O(max{Ai})的。对于极限数据还是可能超时。

另一种动态规划算法需要我们换一种状态表示。我们可以用g[i][j]表示答错i题,答对j题时,能达到的 最好记录 是什么。

这里记录用一个二元组(x, y)表示,其中x是关卡,y是得分。也就是说g[i][j]=(x, y)表示答错i题,答对j题时,最高能进行到第x关,并且得分是y。

显然任何两个记录(x1, y1)和(x2, y2)都是可比较优劣的。同时为了描述方便,我们定义一个记录"加"得分的算子+,(x1, y1) + s = (x2, y2)表示:如果当前在第x1关y1分,那么再加s分之后,到达的是第x2关y2分。

我们可以按答题总数划分阶段,每次转移就是枚举最后一题是答对还是答错了:

g[i][j] = max{g[i-1][j] + T, g[i][j-1] + S}

最后我们在所有g[i][j]里找到通过第n关,并且j最小的。

这个算法总复杂度是O(M^2),转移是O(1)的。


//
// Created by liyuanshuo.
// Author: LiAo/LiYuanShuo
// Time: 2017/4/11.
// CSDN blog: http://blog.csdn.net/liyuanshuo_nuc?skin=dark1
// 顺便骗点访问量(^_^)
//

#include <bits/stdc++.h>

using namespace std;

int dpp[1010][1010];
const int inf = 0x7f7f7f7f;
int array_a[1010];

int main( )
{
	//freopen ("F:\\CSLeaning\\Thinking in C++\\hihocoder\\in.in", "r", stdin);
	
	int q, n, m, s, t;
	cin>>q;
	while( q-- )
	{
		memset (dpp, inf, sizeof (dpp));
		cin>>n>>m>>s>>t;
		for (int i = 1; i <= n  ; ++i)
		{
			cin>>array_a[i];
		}
		for (int j = 0; j <=m ; ++j)
		{
			dpp[0][j] = 0;
		}
		for (int k = 1; k <= n ; ++k)
		{
			int total_num = ( array_a[k]%s == 0 ) ? array_a[k]/s : array_a[k]/s+1 ;
			for (int i = 0; i <= total_num ; ++i)
			{
				int tmp_x = array_a[k] - i*s;
				if( tmp_x > 0 )
					tmp_x = (tmp_x%t == 0 ) ? tmp_x/t : tmp_x/t+1;
				else
					tmp_x = 0;
				for (int j = 0; j+tmp_x+i <= m  ; ++j)
				{
					dpp[k][i+j+tmp_x] = min (dpp[k][i+j+tmp_x], dpp[k-1][j]+i );
				}
			}
		}
		int ans = inf;
		for (int l = 0; l <= m ; ++l)
		{
			ans = min (ans, dpp[n][l]);
		}
		if( ans <= m )
			cout<<ans<<endl;
		else
			cout<<"No"<<endl;
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/liyuanshuo_nuc/article/details/70059816
今日推荐