# Binary Search# Greedy# Problem Solving

c179 - A.門票

🔗 前往 ZeroJudge 原題

題目描述

題目描述了小 Y 和他的同學去遊樂場,需要購買門票的情況。每個人的門票價格不同,小 Y 有 k 張面額相同的鈔票。題目要求找到最小的鈔票面額,使得小 Y 可以支付所有人的門票費用。售票機的支付方式是按照門票價格從小到大順序支付,如果儲值卡餘額不足,則需要額外投入一張鈔票。

解題思路

本題可以使用二分搜尋法來解決。二分搜尋的範圍是從最大的門票價格到所有門票價格的總和。對於每個可能的鈔票面額,我們可以使用貪心策略來模擬售票機的支付過程。如果能夠成功支付所有門票,則說明該面額是可行的,我們嘗試更小的面額。如果無法支付,則說明該面額太小,我們嘗試更大的面額。

具體來說,judge(v) 函數用於判斷給定面額 v 是否可行。它模擬了售票機的支付過程,如果能夠支付完所有門票,則返回 true,否則返回 falsebs(l, r) 函數使用二分搜尋法來找到最小的可行面額。

複雜度分析

  • 時間複雜度: O(N log(Total Sum)),其中 N 是門票數量,Total Sum 是所有門票價格的總和。二分搜尋的範圍是從最大門票價格到總和,每次二分搜尋需要調用 judge 函數,judge 函數的時間複雜度是 O(N)。
  • 空間複雜度: O(1),除了輸入陣列外,程式使用的額外空間是常數級別。

程式碼

#include <stdio.h>
int n,p[200005],k,ma,total;
inline int read(){
	int a(0);
	char c('0');
	while(c>='0'){
		a=(a<<3)+(a<<1)+c-'0';
		c=getchar_unlocked();
	}
	return a;
}
inline void write(int x) {
	if(x==0)
		putchar_unlocked('0');
	else{
		int stk[10],*ptr(&stk[0]);
		while(x){*ptr=x%10;x/=10;++ptr;}
		while(--ptr>=(&stk[0])){putchar_unlocked(*ptr+'0');}
	}
}
inline bool judge(int v){
	if(v<ma)return 0;
	int tk=k,tv=v;
	for(int i=0;i<n;++i){
		if(tv<p[i]){
			tv=v;
			--tk;
			if(tk<=0)return 0;
		}
		tv-=p[i];
	}
	return 1;
}
inline int bs(int l,int r){
	if(l>r)return l;
	int m=(l+r)/2;
	if(judge(m))
		return bs(l,m-1);
	else
		return bs(m+1,r);
}
int main() {
	n=read();
	k=read();
	for(int i=0;i<n;++i){
		p[i]=read();
		if(p[i]>ma)ma=p[i];
		total+=p[i];
	}
	if(n==k)
		write(ma);
	else
		write(bs(ma-1,total+1));
	return 0;
}

Discussion