题意: 有4种操作,你需要用最少的操作使得0变成n.
- × 2 \times2 ×2
- × 3 \times3 ×3
- × 5 \times5 ×5
- ± 1 \pm 1 ±1.
反过来考虑这个问题,
- 2 ∣ n , n / = 2 2|n,n/=2 2∣n,n/=2
- 3 ∣ n , n / = 3 3|n,n/=3 3∣n,n/=3
- 5 ∣ n , n / = 5 5|n,n/=5 5∣n,n/=5
- n ± = 1 n\pm=1 n±=1
有个显然的性质:
最优情况下,对于n,经过若干次
±
\pm
±后再除以
k
(
k
∈
{
2
,
3
,
5
}
)
k(k\in\{2,3,5\})
k(k∈{2,3,5}),得到的值
y
y
y,一定满足
y
∈
[
⌊
n
k
⌋
,
⌈
n
k
⌉
]
y\in [\lfloor\dfrac{n}{k}\rfloor,\lceil\dfrac{n}{k}\rceil]
y∈[⌊kn⌋,⌈kn⌉].
因为如果
y
<
⌊
n
k
⌋
y<\lfloor\dfrac{n}{k}\rfloor
y<⌊kn⌋,那么先除再
±
\pm
±肯定更快.
对于
y
>
⌈
n
k
⌉
y>\lceil\dfrac{n}{k}\rceil
y>⌈kn⌉,同理.
再来一个性质: ⌊ ⌊ n a ⌋ b ⌋ = ⌊ n a b ⌋ , ⌈ ⌈ n a ⌉ b ⌉ = ⌈ n a b ⌉ \lfloor\dfrac{\lfloor\frac{n}{a}\rfloor}{b}\rfloor=\lfloor\dfrac{n}{ab}\rfloor,\lceil\dfrac{\lceil\frac{n}{a}\rceil}{b}\rceil=\lceil\dfrac{n}{ab}\rceil ⌊b⌊an⌋⌋=⌊abn⌋,⌈b⌈an⌉⌉=⌈abn⌉.
然后状态复杂度大概: O ( 6 0 3 ) O(60^3) O(603).
暴力出奇迹!
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define gc getchar()
using namespace std;
typedef long long ll;
template<class o> void qr(o&x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c))x=x*10+c-'0',c=gc;
x*=f;
}
int T;
ll n,a,b,c,d;
map<ll,ll> s;
ll f(ll n) {
if(s.count(n)) return s[n];
ll res=n<1e18/d?n*d:(ll)1e18;
ll l1=(n/2)*2,r1=((n+1)/2)*2;
ll l2=(n/3)*3,r2=((n+2)/3)*3;
ll l3=(n/5)*5,r3=((n+4)/5)*5;
res=min(res,(n-l1)*d+f(l1/2)+a);
res=min(res,(r1-n)*d+f(r1/2)+a);
res=min(res,(n-l2)*d+f(l2/3)+b);
res=min(res,(r2-n)*d+f(r2/3)+b);
res=min(res,(n-l3)*d+f(l3/5)+c);
res=min(res,(r3-n)*d+f(r3/5)+c);
return s[n]=res;
}
int main() {
qr(T); while(T--) {
qr(n); qr(a); qr(b); qr(c); qr(d);
s.clear(); s[0]=0; s[1]=d; printf("%lld\n",f(n));
}
return 0;
}