Function

本文介绍了一种通过枚举g(x)取值(1到54),利用二次函数A*x^2 + B*x的性质,解决特定情况下函数f(x)在给定区间[1,n]上的最小值问题。通过详细分析开口方向和对称轴,针对不同A值提供针对性的搜索策略,包括对称点查找和区间边界处理。
摘要由CSDN通过智能技术生成

传送门

思路

枚举 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;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值