Function

本文介绍了一种优化算法,针对给定的二次函数f(x) = ax^2 + bx + cg^2(x) + dg(x),通过枚举g(x)并利用二次函数特性,通过三分查找找到在区间[1, 1e6]内最小值的方法。博客详细讲解了如何固定g(x)后转化为一元二次函数,并根据不同情况(正比、开口方向)讨论了解题策略。

Function

链接

题解

首先暴力肯定是不行的,考虑怎么优化一下,因为当前这个方程有两个变量 x 和 g(x),所以优先考虑固定一个变量就只剩下一个变量了,而x 属于 [1, 1e6], 因此g(x) 最大也就是99999 这个数转换过去变成54,所以考虑枚举每一个g(x) 然后当g(x) 固定以后,原来式就变成了

f(x)=(ag(x)+b) x ^ 2+(cg^2(x)+d g(x)) x

这种形式的一个二次函数,每一个g(x)的x的取值一定是一个坐标轴上递增的

我们设x ^ 2 的系数为A, x 的系数为 B 进一步就变成了

f(x)=Ax ^ 2 + B x

分类来看:

1. 当A = 0 f(x) 是一个正比例函数,答案一定在左右端点,判断一下就行
2. 当 A < 0 f(x) 开口向下 最小值也一定在两端,判断一下就行
3. 当 A > 0 f(x) 开口向上 最小值应该是极值点,而求极值可以用三分,找一下即可

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
LL n, m, a, b, c, d;
LL get_g(LL x) {
    LL res = 0;
    while (x) {
        res += x % 10;
        x /= 10;
    }
    return res;
}
LL f(LL a, LL b, LL x) {
    return a * x * x + b * x;
}
vector<LL> g[55];
//Ag + b    cg^2 + dg 
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    LL T;
    for (LL i = 1; i <= 1e6; i ++ )
            g[get_g(i)].push_back(i);
    cin >> T;
    while (T -- ) {
        LL res = 1e18; // 开LL
        cin >> a >> b >> c >> d >> n;
        for (LL i = 1; i <= 54; i ++ ) 
            if (g[i].size()) {             
                LL l = 0, r = upper_bound(g[i].begin(), g[i].end(), n) - g[i].begin() - 1;  // 找大于x的第一个数       
                if (l > r) continue;
                LL A = a * i + b, B = c * i * i + d * i;
                if (A <= 0) res = min({res, f(A, B, g[i][0]), f(A, B, g[i][r])});
                else {
                    while (l <= r) { // 三分
                        LL m1 = l + (r - l) / 3, m2 = r - (r - l) / 3;
                        if (f(A, B, g[i][m1]) > f(A, B, g[i][m2])) l = m1 + 1;
                        else r = m2 - 1;                   
                    }
                    res = min(res, f(A, B, g[i][l]));
                }
            }
        cout << res << endl;
    }
return 0;
}
// 99999
// 54
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值