HDU7106 Function(思维+二分)
Posted KaaaterinaX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于HDU7106 Function(思维+二分)的主要内容,如果未能解决你的问题,请参考以下文章
HDU6038-Function-数学+思维-2017多校Team01
HDU 6276 Easy h-index(思维+二分/前缀和)