[usaco月赛]梦幻王国

Description
梦幻王国钱币面值有五种1、7、49、343、2401(即:7^0、7^1、7^2、7^3、7^4)。某人买东西要用现金支付n元,买卖双方可以相互找钱(假设双方各种钱币数量都足够多)。
问:买卖双方最少总共需用多少张钱币?
Input
n(n<=3000)
Output
最少钱币数
Sample Input 12
Sample Output 4
HINT
[样例解释] 买方用2张7元;卖方找2张1元,共4张钱币
[数据范围]
对于50%的数据,n,m<=1500
对于100%的数据,n,m<=3000

The Solution

这道题的思想很显然。

首先,你先把钱数转化为7进制。如(672)10=(1650)7

然后先求单方面给,就是纯加法的运算,这很简单,只需要将7进制下的数字和求出来即可。1+6+5=12。

下一步,就要用到找钱了。思想核心就在这里。怎么找钱呢?

我们先看看如果单看七进制一位上的数字。可以得到4是中间数,这个数无论是纯加法还是找钱所需张数都一样。

即我可以给4张,也可以给你一张比当前大一个面值的,再由你找3张。
便于理解,我举例:钱数是11,7进制是14。不看要给的7块,单从剩余4块分析,我可以给4张1块,也可以给1张7块,你找3张一快,钱的张数都是4。

综上,我们推知,当单个位上的数字≤4的时候,我们可利用纯加法(既然都一样用简单的),当数字>4的时候,我们就用找钱。

继续开头的例子。(1650)7,6>4,5>4,所以应该找钱。怎么找呢?6进一位,所以要给一张7^3也就是343元的代替了6张49元,5进一位,所以也要给一张49元的代替5张7元。

看下面的表格

number7^4=24017^3=3437^2= 497^1= 77^0= 1
给钱21
找钱12

我们发现,给一张49又找一张49,抵消了;给一张7找2张7,抵消了一张。
因此,我们可以把各个位上给钱和找钱的差的绝对值加起来,2+2=3张。
我们来验证一下。672=343*2-7*2。没错。

不懂看标,嘿嘿嘿嘿

Code

c++

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define fd(i,a,b) for (int i=a;i>=b;i--)
#define N 30005
using namespace std;
int a[N];
int main()
{
    int n,k=0,ans=0;
    scanf("%d",&n);
    for (;n;n/=7) a[++k]=n%7;
    fo(i,1,k)
    {
        if (a[i]>=4) a[i]=7-a[i],a[i+1]++;
        ans+=a[i];
    }
    printf("%d",ans);
} 

Pascal

var
    n,i,j,k,ans:longint;
    a:array[0..30000] of longint;
begin
    readln(n);
    for i:=1 to n do
    begin
        k:=k+1;
        a[k]:=n mod 7;
        n:=n div 7;
    end;
    for i:=1 to k do
    begin
        if a[i]>=4 then
        begin
            a[i]:=trunc(7)-a[i];
            a[i+1]:=a[i+1]+1;
        end
        else;
        ans:=ans+a[i];
    end;
    ans:=ans+a[k];
    writeln(ans);
end.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值