HDU7106 Function(思维+二分)

Function
这个题首先思路就很神奇,我还是太菜了一下也没想到。

观察到g(x)的取值范围很小,可以考虑枚举g(x)的取值,然后得到一个系数确定的抛物线,运用二分可以算出最小值。

但是!!

我按照这个思路,对抛物线进行分情况讨论,结果wa了一上午,why??

————对称轴存在误差。

二分传入的参数是整型的,但是对称轴的值很可能是个小数。所以建议枚举对称轴附近的几个点,来避免精度带来的误差。

ac代码如下:

vector<ll>G[100];
inline void init(){
    for(int i=1;i<=1e6;i++){
        int j=i;
        int x=0;
        while (j){
            x+=j%10;
            j/=10;
        }
        G[x].push_back(i);
    }
}

ll a,b,c,d,n;
inline ll f(ll i,ll x){
    return a*x*x*i+b*x*x+c*x*i*i+d*x*i;
}
inline int bin(int l0,int r0,int i,ll n){
    //n is the upper_bound
    int l=l0,r=r0;
    int res=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(G[i][mid]<=n){
            res=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    return res;
}
int main() {
    int t;
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&n);
        ll ans=LINF;
        for(ll i=1;i<=54;i++){
            if(!G[i].size()) continue;
            //先找出n在这个数组的最大下标
            int up=bin(0,(int)G[i].size()-1,(int)i,n);
            if(up==-1) continue;//如果n不在这一组的范围内
            //判断开口方向
            ll A=a*i+b;
            if(A<=0){
                //如果开口向下,或者是一条直线
                ll d1=f(i,G[i][0]);
                ll d2=f(i,G[i][up]);
                ans=min(ans,min(d1,d2));
            }
            else{
                //如果开口向上
                ll dd=-((c*i*i+d*i)/(2*(a*i+b)));
                int x1=bin(0,up,(int)i,dd);
                if(x1==-1) x1=0;
                for(int j=max(0,x1-4);j<=min(up,x1+4);j++){
                    //枚举对称轴附近的几个点
                    ans=min(ans,f(i,G[i][j]));
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KaaaterinaX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值