1. 程式人生 > >hihoCoder之hiho一下 第六十九周 解題

hihoCoder之hiho一下 第六十九周 解題

題目1 : HIHODrinking Game

時間限制:10000ms

單點時限:1000ms

記憶體限制:256MB

        Little Hi and Little Ho are playing adrinking game called HIHO. The game comprises N rounds. Each round, Little Hipours T milliliter of water into Little Ho's cup then Little Ho rolls a K-facesdice to get a random number d among 1 to K. If the remaining water in LittleHo's cup is less than or equal to d milliliter Little Hi gets one score andLittle Ho drinks up the remaining water, otherwise Little Ho gets one score andLittle Ho drinks exactly d milliliter of water from his cup. After N rounds whohas the most scores wins.Here comes the problem. If Little Ho can predict thenumber d of N rounds in the game what is the minimum value of T that makesLittle Ho the winner? You may assume that no matter how much water is added, LittleHo's cup would never be full.

    輸入The firstline contains N(1 <= N <= 100000, N is odd) and K(1 <= K <=100000).The second line contains N numbers, Little Ho's predicted number d of Nrounds.

輸出Output theminimum value of T that makes Little Ho the winner.

樣例輸入

5 6

3 6 6 2 1

樣例輸出

4

解題思路:

該題的目的是要求取出最小的T,並且K的序列以及得分的規則是已知的。因而可以很容易寫出每一個輪迴中

Ho的得分情況。本題中需要讓Ho勝出,總分顯然是NN為奇數),因此,只需要Ho的得分大於N/2即可。在本題的難點主要在於對演算法複雜度的要求,如果採取暴力求解,即T的範圍鎖定在K序列的最小值min,最大值max+1之間,即T的範圍為[min,max+1]。採取這種暴力求解的方式,固然可以求解出來,但是此時計算複雜度較高。因此暴力求解並不是好的方法。這時,我們希望能最好找到得分scoreT之間的一個關係。很明顯的有當T=0時,score=0。當T=max+1時,有score=N。因此,可以猜想scoreT之間是否是存在一個單調遞增的關係。

因此,可以假設:

score = f(T)

而要證明f(T)

函式確實滿足遞增的性質,只需證明對於 T 和 T' (T < T'),每一輪開始時小Ho的得分和剩餘的飲料體積,T 對應的數值都不超過 T' 對應的數值。

我們設s[i]r[i]表示第i輪開始,還沒有新增 T 單位飲料時,小Ho的得分和剩餘飲料的體積;s'[i]r'[i]表示第i輪開始,還沒有新增 T' 單位飲料時,小Ho的得分和剩餘飲料的體積。

我們要證明:對於i = 1..N+1,都有s[i] ≤ s'[i]r[i] ≤ r'[i]

利用數學歸納法,i = 1 時,s[i] = s'[i] = 0r[i] = r'[i] = 0,結論成立。

假設i = n 時結論成立,那麼當i = n+1 時:r[n+1] = max(r[n]+T-d, 0),r'[n+1] = max(r'[n]+T'-d, 0)

由於r[n] ≤ r'[n]T < T',所以r[n]+T < r'[n]+T'

  • d < r[n]+T < r'[n]+T時,r[n+1] = r[n]+T-dr'[n+1] = r'[n]+T'-ds[n+1] = s[n]+1,s'[n+1] = s'[n]+1,易知結論成立;
  • r[n]+T ≤ d < r'[n]+T時,r[n+1] = 0r'[n+1] = r'[n]+T'-d > 0s[n+1] = s[n],s'[n+1] = s'[n]+1,易知結論成立;
  • r[n]+T < r'[n]+T ≤ d時,r[n+1] = r'[n] = 0s[n+1] = s[n]s'[n+1] = s'[n],易知結論成立。

綜上所述,對於i = 1..N+1,都有s[i] ≤ s'[i]r[i] ≤ r'[i]。而f(T) = s[N+1] ≤ s'[N+1] = f(T'),所以函式f(T)是單調遞增的。

得到f(T)是單調遞增的,那麼,我們就可以用二分法求解了,這樣演算法複雜度降低很多。
<span style="color:#333333;">#include<iostream>
using namespace std;

int main(){
	int N;
	int K;
	int T;
	int flag=0;
	cin>>N>>K;
	int d[100000]={0};
	int min=100000;
	int max=0;
	int mid=0;
	
	for(int i=0;i<N;i++){
		cin>>d[i];
		if(min>d[i])
			min=d[i];
		if(max<d[i])
			max=d[i];
	}
	if(min==max){               //</span><span style="color:#ff0000;">此處需要注意,當出現min與max相同時,是不會進入while迴圈的,此時T</span><span style="color:#333333;">
		max++;             //</span><span style="color:#ff0000;">應為max+1</span><span style="color:#333333;">
		T=max;
	}
	else{
		max++;
		while(min+1<max){
			mid=(min+max)/2;
			T=mid;
			int score_O=0;
			int height=0;
			for(int i=0;i<N;i++){
				height+=T;
				if(height<=d[i]){
					height=0;
				}
				else{
					score_O++;
					height-=d[i];
				}
			}
			if(score_O<=N/2){
				min=mid;
			}
			else{
				max=mid;
			}
		}
	}
	T=max;
	cout<<T;
	return 0;
	//delete []d;
}</span>