链接地址:https://acm.uestc.edu.cn/contest/198/problem/J

我们都知道人民币的面值是1、2、5、10,为什么是这个数值呢,我们分析了下发现,从的每个数字都可以由每种面值选出至多一张通过加法和减法(找钱)来构成,(比如:1+2=3,5−1=4,5+1=6,5+2=7,1+2+5=8,10−1=9,

但是实际上,我们只需要1、2、7三种面值就可以组成的每一个数字了

1+2=3,7−1−2=4,7−2=5,7−1=6,7+1=8,7+2=9,7+1+2=10

那么现在问题来了,给一个数,请问最少需要多少种不同的面值就可以构成从的所有数字,注意在构成每一个数字时同种面值不能超过张。

Standard Input

一个数字(1<=<=100000)、

Standard Output

一个数字,代表最少需要多少种不同的面值可以构成从的所有数字。

Samples

InputOutput
10
3
Time Limit1000 ms
Memory Limit64 MiB
Output Limit64 MiB

题解与思路:

方法一思路:将该题的实质转化为三进制问题,如果加面额则为+1,减去面额则为-1,不用该面额的纸币则为0;所以n张纸币则有3n种情况(打个比方:如果有两张纸币,则状态共有0 0,1 0,-1 0,0 1,1 1,-1 1,0 -1,1 -1,-1 -1共9种),首先很明显能除去n张纸币状态全为0的情况,剩余3n-1种情况,剩余情况中有一半面额之和为负。举个例子:目前有两张纸币面额分别为1,3,则有32-1=8种情况,即1+0=1 , 3-1=2 , 3+0=3 , 3+1=4 , -1+0=-1 , 1-3=-2 , -3+0=-3 , -1+(-3)=-4,可以看出,正数情况和负数情况是相等的,所以正情况一共有3n-1/2种

疑问:正情况只代表了最大值和最小值的取值范围,怎么能够证明出这个范围区间内的所有值都能取到?

证明:利用数学归纳法,很明显,k=1时明显成立(1元最少只用一张纸币,纸币面额为1),k=3时,能表示[1~4]的所有面额,表示的最大数刚好为正情况的最多种数(即3n-1/2种),假设k=n-1时也成立(纸币面额为1,3,9······3n-2)此时n-1张纸币能表示的范围为[1~3n-1-1/2],当k=n时(纸币面额为1,3······3n-1即新增加的面额为3n-1),新增加的表示范围为[3n-1+1/2~3n-1/2]=>证明1:因为k=n-1时所能表示的正范围为[1~3n-1-1/2],由上面的思路可得,负数和正数的情况是对称的,所以能表示的全范围应该是[-(3n-1-1/2)~3n-1-1/2],此时加上一个新的数3n-1,则将整个区间向前位移3n-1

得新增加的区间[3n-1+1/2~3n-1/2]。此时将新增加的区间和原区间进行合并可得k=n所能表示的区间为[1~3n-1/2](3n-1/2不是整数!),故得证;


方法二思路:不妨设目前能表示的范围为[1~M],此时增加一个数Q>M,由上面证明中的证明1可得,新增加的可表示范围为[Q-M~Q+M],要使得增加一个数Q后的区间所能表示的范围更大,并且区间连续无中断,即Q-M=M+1 => Q=2*M+1,所以增加Q后的最大表示范围为[1~3*M+1],由于我们能知道当人民币面额为1时所能表示的区间为[]1~1],此时只要区间最大值M不超过n,则可以增加一个数Q,使得区间最大值变为3*M+1,直到n包含在区间内;


方法二的实现代码如下:

#includeusing namespace std;int main(){   int n,max=1,count=1;   cin>>n;   if(n==1)   cout<<count<<endl;   else   {     while(max<n)     {         max=3*max+1;         count++;       }    cout<<count<<endl;   }   return 0;}