今天讲二分精确题型
目录
题目:kotori的设备
思路:
题目:银行贷款
思路:
题目:一元三次方程求解
思路:
题目:kotori的设备
思路:
求:设备最长使用时间
二分查找:对使用时间进行二分查找
二分依据:该时间可提供的能量(对比该时间需要补充的能量,若超过则增加时间找最优解)
#include <iostream>
using namespace std;
int n;
double sum,p,l=0,r=1e10;
double a[200000],b[200000];
int check(double ans){
double q=p*ans;//这个时间可提供的能量
sum=0;
for(int i=0;i<n;i++){
if(a[i]*ans<=b[i]) continue;//设备在该时间内不需要充电
sum+=(a[i]*ans-b[i]);//否则就计算还需要的额外能量
}
return sum<=q;//需要的能量小于等于充电器提供的,则这个时间可以做解
}
int main(){
cin>>n>>p;
for(int i=0;i<n;i++){
cin>>a[i]>>b[i];
sum+=a[i];
}
if(sum<=p){ //若所有设备的消耗能量速度总和还是小于充电器的充电速度,输出-1。
cout<<-1.000000<<endl;
return 0;
}
while(r-l>1e-6){ //和标准答案相差小于10e-4即可
double mid=(l+r)/2;
if(check(mid)) l=mid;//如果mid可以做解,就向右逼近
else r=mid; //如果不能做解,就向左找解
}
cout<<l<<endl;
//二分精确就简单多了,r-l控制好精度,到时候就不需要管=在哪里,不需要管输出l,r,mid
return 0;
}
题目:银行贷款
思路:
题意就是在换完每月的钱后,到12月时钱恰好为pay*mon,也就是loan=loan*(1+ans)-pay经过12次循环后为0或逼近0
求:月利率
二分查找:对利率进行二分查找(二分精确)
二分依据:该利率下12个月后的贷款
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
int loan,pay,mon;
double l=0,r=10,mid,t; //利率可能大于1
cin>>loan>>pay>>mon;
while(r-l>0.0001){
mid=(l+r)/2;
t=loan;
for(int i=0;i<mon;i++){
t=t*(1+mid)-pay;
}
if(t>0) r=mid; //t大于0说明利率太大了,那就调小利率
else if(t<0) l=mid;
else{
printf("%.1f",mid*100); //(找理想解)可以直接输出
return 0;
}
}
printf("%.1f",mid*100); //保留小数点后一位
return 0;
}
题目:一元三次方程求解
思路:
二分查找:对解进行二分
二分依据:零点定理
#include<cstdio>
double a,b,c,d;
double f(double x) //输入自变量,返回函数值
{
return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
double l,r,mid,x1,x2;
int ans=0,i; //ans是答案个数
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
for (i=-100;i<100;i++)
{
l=i; r=i+1; x1=f(l); x2=f(r); //将每个i分成[i,i+1]区间,然后处理f(i)和f(i+1)符号
if(x1==0) //若i刚好命中就输出(即左端点i刚好是零点)
{
printf("%.2lf ",l); ans++; //不能判断右端点,会重复
}
if(x1*x2<0) //根落在区间时就二分查找
{
while(r-l>=0.001)//控制精度
{
mid=(l+r)/2;
if(f(mid)*f(r)<=0) l=mid; //向右压缩
else r=mid; //向左压缩
}
printf("%.2lf ",r); //左右都可以
ans++;
}
if (ans==3) break;
}
return 0;
}