Function(三分+预处理)

题目描述:

传送门

如果不知道三分的可以看看这个传送门

令$g(x)$为$x$中各位数和,例如$g(123456)=1+2+3+4+5+6$,然后有T次询问,每次询问给你一个$a$,$b$,$c$,$d$,$n$

让你求$f(x)=Ax^{2}g(x)+Bx^{2}+Cxg^{2}(x)+Dxg(x)$

解题思路:

原式:$f(x)=Ax^{2}g(x)+Bx^{2}+Cxg^{2}(x)+Dxg(x)$

$g(x)$ 为 $x$各位上的数字总和,而 $x$ 的数据范围是 $1$ 到 $1e6$,因此可直接算出 $g[x]$ 的最大值,即$g[999999]=54$。

所以$g(x)$只有$54$种不同的值,令 $g(x)=i$,当$i$确定后$f(x)$就成了关于$x$的二次函数,然后求它的最小值即可。

设$A=a*i+b$,$B=c*i^{2}+d*i$。

那么原式就可以转化成 $f(x)=A*x^{2}+B*x$

因此可先预处理满足$g(x)==i$的$x$值,然后枚举$i$从$1$到$54$,并去找最小值。

找最小值时应注意$A$的正负情况。

  • 若 $A<=0$,则最小值出现在该二次函数的左右两侧
  • 若 $A>0$,则需要用三分去找 $l$ 到 $r$ 中离对称轴最近的那个点(或直接找最小值)

Code

 

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
vector<int>v[60];
ll ans[maxn];
ll A,B;
struct node{
    int id;
    ll a,b,c,d,n;
    bool friend operator<(node x,node y){
        return x.n<y.n;
    }
}q[maxn];
ll get_g(int x){
    ll ans=0;
    while(x){
        ans+=x%10;
        x/=10;
    }
    return ans;
} 
ll get_f(ll x){
    return A*x*x+B*x; 
}
ll solve(int u){
    ll a,b,c,d,n;
    a=q[u].a,b=q[u].b,c=q[u].c,d=q[u].d,n=q[u].n;
    ll ans=6e18;
    for(int i=1;i<=54;i++){
        if(v[i].size()==0){
            continue;
        }
        A=a*i+b,B=c*i*i+d*i;
        if(A<=0){
            ans=min(ans,get_f(v[i][0]));
            ans=min(ans,get_f(v[i][v[i].size()-1]));
        }
        else{
            int l=0,r=v[i].size()-1;
            while(l<r){
                int lmid=l+(r-l)/3,rmid=r-(r-l)/3;
                if(get_f(v[i][lmid])>get_f(v[i][rmid])){
                    l=lmid+1;
                }
                else{
                    r=rmid-1;
                }
            }
            ans=min(ans,get_f(v[i][l]));
            ans=min(ans,get_f(v[i][r])); 
        }    
    }
    return ans;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        q[i].id=i;
        scanf("%lld%lld%lld%lld%lld",&q[i].a,&q[i].b,&q[i].c,&q[i].d,&q[i].n);
    } 
    sort(q+1,q+n+1);
    int z=1;
    for(int i=1;i<=n;i++){
        while(z<=q[i].n){
            v[get_g(z)].push_back(z);
            z++; 
        }
        ans[q[i].id]=solve(i);
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<"\n";
    }
}

 

posted @ 2021-08-29 19:31  lipu123  阅读(47)  评论(0)    收藏  举报