SRM707 div1 MultiplyAddPuzzle

本文介绍了一种算法来解决一个特定的问题:如何用最少的操作步骤将初始值通过加法和乘法操作达到目标值。文章详细阐述了解决方案的思路,并提供了完整的代码实现。

题目大意:给定4个数,s,t,a,b

每次可以将s加a或者乘b,问最少多少次可以得到t

 

做法:考虑最后的形式,肯定是s*b^n + a*f(b),f(b)是关于b的多项式

那么b乘多少次实际上是可以知道的,然后枚举b的次数n

知道了t - s*b^n,接下来就是求f(b)了

可以知道,按照b进制做是最优的。

这里不能只算最大的n,我是把n从0到最大都算了一遍

因为有些情况较小的n得出的答案会更优。

还有这题的特殊情况相当多orz

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <typeinfo>
#include <fstream>
using namespace std;
typedef long long LL;
int f[100];
class MultiplyAddPuzzle {
    public:
    long long minimalSteps(long long s, long long t, long long a, long long b) {
        if(s > t && b != 0) return -1;
        if(s == t) return 0;
        if(b == 1){
            if(a == 0) return -1;
            if( (t-s)%a != 0) return -1;
            return (t-s)/a;
        }
        if(b == 0){
            if(t == 0) return 1;
            if(a == 0) return -1;
            if(t > s && (t-s)%a == 0) return (t-s)/a;
            if( t%a == 0) return t/a+1;
            return -1;
        }
        if(a == 0){
            if(s == 0) return -1;
            if(t%s != 0) return -1;
            LL temp = t/s, ans = 0;
            while(temp != 1){
                if(temp % b != 0) return -1;
                ans++; temp /= b;
            }
            return ans;
        }
        LL bt = 0, bpow = 1, temp = 0;
        while(s <= t/bpow){
            if( (t-s*bpow)%a == 0) f[bt] = 1, temp = bt;
            bt++;
            if(bpow > 2e18/b) break;
            bpow *= b;
        }
        bt = temp;
        if(bt == 0) { if( (t-s)%a != 0) return -1; else return (t-s)/a; }
        temp = 1;
        LL ANS = f[0] == 1 ? (t-s)/a : 2e18;
        for(int i = 1; i <= bt; i++) {
            temp *= b;
            if(!f[i]) continue;
            bpow = temp;
            LL ans = i, res = (t-s*bpow)/a;
            while(res > 0){
                ans += res/bpow;
                res %= bpow;
                bpow /= b;
            }
            ANS = min(ANS, ans);
        }
        return ANS;
    }
};

 

转载于:https://www.cnblogs.com/Saurus/p/7106401.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值