Codeforces Round #466 (Div. 2) T2题解

原题链接
http://codeforces.com/contest/940/problem/B
题目大意:
给你四个数字,n,k,a,b,拥有以下规则
1:(当n可以整除k时)每一步可以有两种选择
n/k

n-1
2:当你选择n/k时,费用+b
选择n-1时 ,费用+a
3:重复1,2直到n=1,输出费用;

题面
B. Our Tanya is Crying Out Loud
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Right now she actually isn’t. But she will be, if you don’t solve this problem.

You are given integers n, k, A and B. There is a number x, which is initially equal to n. You are allowed to perform two types of operations:

Subtract 1 from x. This operation costs you A coins.
Divide x by k. Can be performed only if x is divisible by k. This operation costs you B coins.
What is the minimum amount of coins you have to pay to make x equal to 1?
Input
The first line contains a single integer n (1 ≤ n ≤ 2·109).

The second line contains a single integer k (1 ≤ k ≤ 2·109).

The third line contains a single integer A (1 ≤ A ≤ 2·109).

The fourth line contains a single integer B (1 ≤ B ≤ 2·109).

Output
Output a single integer — the minimum amount of coins you have to pay to make x equal to 1.

Examples
inputCopy
9
2
3
1
output
6
inputCopy
5
5
2
20
output
8
inputCopy
19
3
4
2
output
12
Note
In the first testcase, the optimal strategy is as follows:

Subtract 1 from x (9 → 8) paying 3 coins.
Divide x by 2 (8 → 4) paying 1 coin.
Divide x by 2 (4 → 2) paying 1 coin.
Divide x by 2 (2 → 1) paying 1 coin.
The total cost is 6 coins.

In the second test case the optimal strategy is to subtract 1 from x 4 times paying 8 coins in total.

本人蒟蒻一枚,因此直到瞄了一眼某神犇的题解,由此有了思路
神犇题解:
http://shizhecheng.blog.163.com/blog/static/304640376201812594620665/?newFollowBlog

思路:一道裸贪心问题(不过我不明白为啥有大佬用DP),每次不要判断-1还是/k,而是每次都/k,若是无法整除k就让n减去n/k的余数再除;否则/k(费用统一处理)
代码

#include<bits/stdc++.h>
#define ll long long//个人爱好
using namespace std;
ll n,k,a,b;
ll coin;//费用
int main() {
    ios::sync_with_stdio(false);//据说可以关闭cin,cout与scanf,printf的同步,提升运行速度
    cin>>n>>k>>a>>b;//输入
    if(k==1) {//特判,如果k=1那么直接输出一直-1的结果(n/1=n若无此特判卡第6,12,23,37,44测试点,亲身经历)
        cout<<a*(n-1)<<endl;
        return 0;
    }
    while(n!=1) {//循环条件:n>1
        if(n<k) {//如果(n<k)即无论如何都无法执行广义的n/k操作
            coin+=(n-1)*a;//直接将剩下的使用-1操作
            n=1;
            continue;//这两句可使用break代替
        }
        ll v=n/k;//long long为(长)整形,整形/整形=整形 利用了整形的性质
        if(n%k) {//无法整除
            ll m=n%k;//n/k的余数
            coin+=min(m*a+b,(n-v)*a);//一减一除也许还不如一直减,进行最小值判断
            //注意,此处的m*a+b与(n-v)*a都是费用,是两种不同方案的费用
            //与操作/k或-1无关,执行只有一个结果,那就是n=n/k;
            //这里只是两种操作方式不同的费用,亲身体验过混淆的感觉
        } else//可以整除
            coin+=min((n-v)*a,b);//同上,在/与-之间选择最小费用
        n/=k;//每次使n/k,即时间复杂度为O(logn(以k为底))
    }
    cout<<coin<<endl;//输出
    return 0;//程序要休息喽
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值