[CCF1034]钞票兑换

题目描述

将任意给定的整百元钞票,兑换成10元、20元、50元小钞票形式。输出兑换方案总数。

输入

输入需要兑换的钞票总数n。

输出

输出方案总数。

样例输入

100

样例输出

10

数据范围限制

100<=n<=1000000


常规0

#include <stdio.h>
#include <stdlib.h>
int main(){
    int i,a,b,c,sum=0;
    scanf("%d",&i);
    for(a=0;a<=i/50;a++){
        for(b=0;b<=i/20;b++){
            for(c=0;c<=i/10;c++){
                if(a*50+b*20+c*10==i){
                    sum++;
                }
            }
        }
    }
    printf("%d",sum);
    return 0;
}

穷举法很容易想到,只要让3个整数挨个穷举就可以了。
虽然还可以在循环范围上进行优化,不过那在接下来的改进面前算不了什么。
但是因为数据范围的问题,会超时TLE,不得不让我们动起了歪脑筋(可能在大佬中就是正常思路)。
为了在文中方便讨论,代码中的i文中变成100i

改进1

因为题目的数据十分友善,可以利用一下。
数学点的描述: 50 a + 20 b + 10 c = 100 i ( a , b , c , i N )
看c好欺负: c = 10 i 5 a 2 b N
当c存在时符合条件: 50 a + 20 b 100 i
这样,就可以消去一个元。

//...
for(a=0;a<=i/50;a++){
    for(b=0;b<=i/20;b++){
        if(a*50+b*20<=i){
            sum++;
        }
    }
}
//...

改进2

这当然不是最终形态啦,还可以改进的更加优秀。
既然c可以算出来,那b可不可以呢?
易解得 0 b 5 i 2.5 a
然后就很容易计算出sum在b的一次循环内增加了多少,但要注意取整的界限问题

//...
for(a=0;a<=i/50;a++){
    sum+=(i-50*a)/20+1;
}
//...

改进3—超进化

没错,已经简单成这样了还能简化,如果不能这么皮还写这篇干什么
官方题解中几乎都是这个级别,但csdn上却搜不到,很奇怪。
那就自己写一篇吧!
刚才本质上已经相当于数列求和,把a=0单独提出

s u m = a = 0 2 i ( I N T ( 5 i 2.5 a ) + 1 ) = 5 i + 1 + a = 1 2 i ( I N T ( 5 i 2.5 a ) + 1 )

展开,分奇偶讨论,去掉取整
= 5 i + 1 + a = 0 i ( I N T ( 5 i 2.5 ( 2 a 1 ) ) + I N T ( 5 i 2.5 ( 2 a ) ) + 2 )
= 5 i + 1 + a = 0 i ( 10 i 10 a + 4 )
s u m = 5 i 2 + 4 i + 1

简化成这样,配的上超进化这个名字
最终代码

#include <stdio.h>
#include <stdlib.h>
int main(){
    int i;
    scanf("%d",&i);
    i/=100;
    printf("%d",5*i*i+4*i+1);
    return 0;
}

完结撒花
2018年8月2日02点31分

猜你喜欢

转载自blog.csdn.net/aiw_prton/article/details/81351161