思路
枚举 g(x) ( g(x) 的范围是[1,54] ),则 g(x)、a、b、c、d 已知,那么我们可以得到一个二次函数
即:A * x^2 + B * x
A:a * g(x) + b
B:c * g(x) * g(x) + d * g(x)
ps:我这里的 a、b、c、d、A、B 指得是我代码中的 a、b、c、d、A、B
A > 0 时:开口向上,最小值在 x0 附近,x0:对称点 即 -B / (2 * A)
A < 0 时:开口向下,最小值在两端
A = 0 时:变为一条直线
注意一点:使得 f(x) 最小的 x,需同时满足: x属于[1,n] 且 g(x) 等于当前枚举到的 g(x)
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 60;
vector<ll> g[N];
ll a,b,c,d,n;
ll A,B;
int run(int x){
int res=0;
while(x){
res+=x%10;
x/=10;
}
return res;
}
void Init(){
for(int i=1;i<=1000000;i++) g[run(i)].push_back(i);
}
ll solve_A(ll x){
return a*x+b;
}
ll solve_B(ll x){
return c*x*x+d*x;
}
ll f(ll x){
return A*x*x+B*x;
}
int main(){
Init();
int T; scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&n);
ll minm=8e18;
for(int i=1;i<=54;i++){
A=solve_A(i),B=solve_B(i);
if(A>0){
ll x0=-B/(2*A); // 对称点
int l=g[i].size();
if(n<=x0){
int j=upper_bound(g[i].begin(),g[i].end(),n)-g[i].begin();
if(j!=0&&g[i][j-1]<=n) minm=min(minm,f(g[i][j-1]));
}
else{
int j=lower_bound(g[i].begin(),g[i].end(),x0)-g[i].begin();
if(j==0&&g[i][j]<=n) minm=min(minm,f(g[i][j]));
else if(j==l&&g[i][l-1]<=n) minm=min(minm,f(g[i][l-1]));
else if(j>0&&j<l){
if(g[i][j]==x0) minm=min(minm,f(g[i][j]));
else{
if(g[i][j]<=n) minm=min(minm,f(g[i][j]));
if(j-1>=0&&g[i][j-1]<=n) minm=min(minm,f(g[i][j-1]));
}
}
}
}
else if(A<0){
int j=upper_bound(g[i].begin(),g[i].end(),n)-g[i].begin();
if(j-1>=0&&g[i][j-1]<=n) minm=min(minm,f(g[i][j-1]));
if(g[i][0]<=n) minm=min(minm,f(g[i][0]));
}
else if(A==0){
if(B>0&&g[i][0]<=n) minm=min(minm,f(g[i][0]));
else if(B<0){
int j=upper_bound(g[i].begin(),g[i].end(),n)-g[i].begin();
if(j-1>=0&&g[i][j-1]<=n) minm=min(minm,f(g[i][j-1]));
}
else if(B==0) minm=min(minm,(ll)0);
}
}
printf("%lld\n",minm);
}
return 0;
}