题目(后面有中文大意)
Our dear Sultan is visiting a country where there are n different types of coin. He wants to collect as many different types of coin as you can. Now if he wants to withdraw X amount of money from a Bank, the Bank will give him this money using following algorithm.
withdraw(X){
if( X == 0) return;
Let Y be the highest valued coin that does not exceed X.
Give the customer Y valued coin.
withdraw(X-Y);
}
Now Sultan can withdraw any amount of money from the Bank. He should maximize the number of different coins that he can collect in a single withdrawal.
Input:
First line of the input contains T the number of test cases. Each of the test cases starts with n (1≤n≤1000), the number of different types of coin. Next line contains n integers C1, C2, … , Cn the value of each coin type. C1< C2< C3< … < Cn<1000000000. C1 equals to 1.
Output:
For each test case output one line denoting the maximum number of coins that Sultan can collect in a single withdrawal. He can withdraw infinite amount of money from the Bank.
Sample Input
2
6
1 2 4 8 16 32
6
1 3 6 8 15 20
Sample Output
6
4
题目大意
你要从银行取价值X的钱,有n种不同的硬币,银行给钱时会执行一个递归程序:
取钱(X){
if(X==0)return;
给你<=X的最大硬币Y;
取钱(X-Y);
}
你的目的是要取得硬币种类尽可能多,输入n(1<=n<=1000),和每种硬币的面值,输出最大种类数。
题解
思路:贪心
首先,假设从1到i被选中的硬币的和是sum[i],第i个硬币的值是a[i],那么当sum[i]< a[i+1]的时候,就可以在保持原来选的同时,选上第i+1个。(证明:假设sum[i]>=a[i+1],那么要选,一开始的数字就是sum[i],而sum[i]>=a[i+1],那么就可以选一次i+1,然后剩下的数字就不够sum[i]了,无法选够原来的了,此时假设不成立,即sum[i]< a[j])
由上述规律即可推出可以选一个数字i的两个条件:1.sum[i-1]< a[i];2.sum[i] (=sum[i-1]+a[i])< a[i+1];满足上述条件的情况下,就可以选这个数字了。
还有,一定要选第一个和最后一个(一样可以用反证法证明)
Then,注意要特判2以下的情况。
最后还有一点小优化:这个递推过程是单向且线性的,那么sum数组就可以简单地用一个sum变量来代替了(不过说实话没什么大用)
代码请参见文尾。
说点儿题外话:我一开始想到的确实是这个思路,可是马上被推翻了,因为按以往经验普及最后一道题总是特别难,不可能这么简单,于是想了一个dp+二分查找,才算觉得够难度了,可是,结果10分,我的内心是崩溃的O_O,惨痛的教训就是永远不要想当然,也不要相信样例(我就是这个算法过了样例)
还有,如果你是初一或初二,那么好好学oi吧,不要来机房混日子(我看见考试时有好几个人玩三维弹球,蜘蛛纸牌),来混日子还不如回去学文化课,还不如早日AFO(Away From OI)。不过,我还是认为这个行业是很有出路的。
如果要学OI的话,就利用好寒假和暑假,平常缓慢学习,积累经验,假期做出质的突破。
还有,不能眼高手低,不能遇难而退,不能半途而废。
最后,祝好好学习OI的人取得NOIP普及组一等奖(看看你们有几个,当年就我一个)
#include<bits/stdc++.h>
using namespace std;
int t,n,a[1005];
int main(){
//建议你们用scanf和printf,会快很多
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%d",&n);
for(int j=1;j<=n;j++){
scanf("%d",&a[j]);
}
if(n<=2){//要特判2以下的情况
printf("%d\n",n);
continue;
}
int sum=a[1];
int cnt=2;//Ñ¡µÚÒ»¸öºÍ×îºóÒ»¸ö
for(int i=2;i<=n-1;i++){
if(sum<a[i]&&sum+a[i]<a[i+1]){
sum+=a[i];
cnt++;
}
}
printf("%d\n",cnt);
}
return 0;
}