题目大意:给定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; } };