二分与三分(备赛中)
创始人
2024-05-29 14:24:02
0

A.愤怒的牛儿

思路:找出最长距离,与最小距离,用二分法判断,如果当前距离满足放牛要求,就把距离区间l=mid+1;如果距离不合适就说明当前距离太大了,把区间变小r=mid-1;最后直到l
#include
using namespace std;
const int maxn=1e9+10;
int num[100010];
int n,m;
int judge(int dis)
{int dum=1;int xi=num[1];for(int i=2;i<=n;i++){if(num[i]-xi>=dis){dum++;xi=num[i];}if(dum==m)break;}return dum==m;}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++)cin>>num[i];sort(num+1,num+1+n);int l=num[1];int r=num[n]-num[1]+1;int k;while(l>1;if(judge(mid)){k=mid;l=mid+1;}else r=mid;}cout<

B.Best Cow Fences

思路:看到了平均值就知道应该要用前缀和了,我们要输出平均数最大的,当然就要考虑用二分了。我们依旧用二分法,每一次如果该平均值满足条件,我们就把区间l=mid;(这里为什么不l=mid+1;因为这样会跳过答案)。如何判断呢就是我们用前缀和,前缀和在开始的时候要把传过来的平均值直接减去,看看是否小于0即可。取最大平均值过程中是这样的,把前面最小的保存下来。然后用后面的减去那个最小值看看是否大于0即可。最好输出即可l或r。

#include
using namespace std;
const int maxn=1e5+10;
int n,m;
double num1[maxn];
double num2[maxn];
bool judge(double ave)
{for(int i=1;i<=n;i++)num2[i]=num2[i-1]+num1[i]-ave;//每次都减去平均值double mins=maxn;//筛出最小前缀值for(int i=m;i<=n;i++)//从最短距离开始{mins=min(num2[i-m],mins);if(num2[i]-mins>0)return true;}return false;
}
int main()
{cin>>n>>m;double l=0,r=0;for(int i=1;i<=n;i++){cin>>num1[i];r=max(num1[i],r);}while(r-l>1e-6){double mid=(l+r)/2;if(judge(mid))l=mid;else r=mid;}printf("%d\n",(int)(1000*r));
}

C.曲线

 思路:单峰函数用三分法。具体方法如下。

#include
using namespace std;
int num;
int num1;
double a[20005],b[20005],c[20005];
double judge(double x)//返回值
{double mas=INT_MIN;for(int i=1;i<=num1;i++){mas=max(mas,a[i]*x*x+b[i]*x+c[i]);//选出最大的那个值}return mas;
}
void solves()
{cin>>num1;for(int i=1;i<=num1;i++){cin>>a[i]>>b[i]>>c[i];}double left=0,right=1000;while(right>left+1e-4)//精度{double midleft=left+(right-left)/3;//三分左区间double midright=right-(right-left)/3;//三分右区间if(judge(midleft)>=judge(midright))//如果左高的话说明左离得远{left=midleft;//移动左区间}else right=midright;//否则移动右区间}printf("%.4f\n",judge(left));}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>num;while(num--){solves();}
}

D.数列分段

 思路:依旧是二分思路,取全和做R,取1做L,移动区间即可。对于满足条件就把区间r=mid,不满足条件就l=mid+1;最后输出r。判断函数写法具体是,看看是否能在段数不大于m的情况,满足条件。

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n,m;
ll num[maxn];
int check(int x)
{ll sum=0;int cnt=1;for(int i=1;i<=n;i++){if(num[i]>x)return 0;sum+=num[i];if(sum>x){sum=num[i];cnt++;}}return m>=cnt;
}
int main()
{cin>>n>>m;int l=1,r=0;for(int i=1;i<=n;i++){cin>>num[i];r+=num[i];}while(l>1;if(check(mid))r=mid;else l=mid+1;}cout<

E.扩散

 思路:依旧是二分,但需要并查集的协助,我们设置最大时间R=1e9+10,最小时间L=0.我们开始二分算法,如果当前时间满足条件,就把时间区间R=mid;否则L=mid+1.最后输出R。判断函数具体思路是我们设置二重循环,每一次访问两个点看看能不能在当前时间内是否能扩散相交。具体条件是x,y坐标差值与两倍时间的大小关系。如果小于或等于则可以扩散到,反之则不可以。如果扩散到的话就,放到并查集中,如果没有就不用放。之后看看每个点是否只有一个祖先即可。

#include
using namespace std;
const int maxn=1e6+10;
int x[maxn],y[maxn];
int father[maxn];
int n;
int find(int x)
{if(father[x]==x)return x;else return find(father[x]);
}
bool check(int mid)
{int sum=0;for(int i=1;i<=n;i++)father[i]=i;for(int i=1;i<=n;i++){for(int i1=i+1;i1<=n;i1++){if(abs(x[i]-x[i1])+abs(y[i]-y[i1])<=2*mid){if(find(i)!=find(i1)){father[find(i)]=find(i1);}}}}for(int i=1;i<=n;i++){if(father[i]==i)sum++;if(sum==2)return false;}return true;}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;for(int i=1;i<=n;i++){cin>>x[i]>>y[i];}int l=0,r=1e9+10;int ans;while(l>1;if(check(mid)){r=mid;}else l=mid+1;}cout<

H.灯泡

 

 思路:根据计算所得影子长度就两种情况

(1)当影子不会射到墙上时,影子长度为

(2)当影子射到了墙上时,影子长度为

看函数我们将x定义为等到人的距离。看函数是一个单峰函数。所以用三分法去做。具体如下

​
#include
using namespace std;
double H,h,D;
double check(double x)
{if(D-x>h*x/(H-h))//影子长度小于人到墙的距离{return h*x/(H-h);//返回第一种情况}else{return D-x+h-(H-h)*(D-x)/x;//反之影子在墙上,返回第二种情况。}
}
void solve()
{cin>>H>>h>>D;double l=0;double r=D;while(r-l>1e-6){double midl=l+(r-l)/3;double midr=r-(r-l)/3;if(check(midl)>=check(midr))//单峰函数移动法{r=midr;}else l=midl;}printf("%.3f\n",check(r));
}
int main()
{int num;cin>>num;while(num--){solve();}
}​

 G.传送带

 思路:这道题有点难度,想了好久,学习了好久才会的。共有三段路程,一段在AB上,一段在CD上,还有一段在路上。很简单看一下,那个最少时间满足单谷函数。所以我们用三分,但未知量有两个所以我们用三分套三分。具体如下

#include
using namespace std;
double Ax,Ay,Bx,By,Cx,Cy,Dx,Dy,p,q,r,ans;
double check(double x,double y)
{double P1x=Ax+(Bx-Ax)*x,P1y=Ay+(By-Ay)*x,P2x=Cx+(Dx-Cx)*y,P2y=Cy+(Dy-Cy)*y;return sqrt((P1x-Ax)*(P1x-Ax)+(P1y-Ay)*(P1y-Ay))/p+sqrt((Dx-P2x)*(Dx-P2x)+(Dy-P2y)*(Dy-P2y))/q+sqrt((P2x-P1x)*(P2x-P1x)+(P2y-P1y)*(P2y-P1y))/r;
}
double find2(double x,double l,double r)//在CD上三分
{double res=0.0;//返回的时间数while(r-l>=1e-6)//精度{double midl=l+(r-l)/3;double midr=r-(r-l)/3;double res1=check(x,midl);//按在AB中的比例,和CD中的比例返回时间double res2=check(x,midr);if(res1=1e-6){double midl=l+(r-l)/3;//在AB上三分double midr=r-(r-l)/3;double res1=find2(midl,0,1);//用三分出来的比例在CD上看返回来的值分布情况double res2=find2(midr,0,1);if(res1>Ax>>Ay>>Bx>>By>>Cx>>Cy>>Dx>>Dy>>p>>q>>r;//输入find1(0,1);//这里的0,1是在AB上的比例。printf("%.2f",ans);
}

相关内容

热门资讯

江南三大名人,分别是那些人? 江南三大名人,分别是那些人?   唐伯虎妙写对联  从前,苏州街上有个南货店老板,求名士唐伯虎写副...
离退休人名参观养老院 离退休人名参观养老院正对离退休人员的养老有地方是以政府购买服务的方式让其入住本地好些的专业养老社区或...
电影财神客栈的拼音 电影财神客栈的拼音财神 cai 第二声 shen 第二声客栈 ke 第四声 zhan 第四声cais...
宠辱不惊 看庭前花开花落 ... 宠辱不惊 看庭前花开花落 去留无意 望天上云卷云舒的作者?年代?谢谢!《幽窗小记》中有这样一幅对...
怎么从任务管理器打开我的电脑? 怎么从任务管理器打开我的电脑?explorer.exe被破坏,无论是正常启动还是进安全模式,都提示e...
春望唐代诗人杜甫写的从题目上看... 春望唐代诗人杜甫写的从题目上看这首诗是诗人在什么季节的时候描写的?春望是唐代诗人杜甫在春天季节来写的...
丧偶式婚姻让人难过,是该继续坚... 丧偶式婚姻让人难过,是该继续坚持还是应该潇洒离开?潇洒离开。因为这样的婚姻名存实亡,没有任何感情,已...
把一个故事说好有哪些技巧? 把一个故事说好有哪些技巧?讲故事,最重要的是对何事的讲解,换句话说也就是重现场景,重现场景的一个技巧...
努力努力再努力繁体字 努力努力再努力繁体字努力努力再努力繁体字努力努力再努力繁体字还是(努力努力再努力)
我姓徐请帮忙给我女儿起个好听的... 我姓徐请帮忙给我女儿起个好听的名字谢谢大家徐清妍:美好。适用于女孩取名字。出自唐代韩愈《月池》诗:“...
沙之守鹤九尾到底什么关系?总共... 沙之守鹤九尾到底什么关系?总共有几个尾?沙之守鹤是一尾,他和九尾没啥关系,只是同为怪物吧...一尾守...
探索的意思是什么拜托了各位 谢... 探索的意思是什么拜托了各位 谢谢探索一般是指对自然未知部分的探索性发掘.是指人的一种行为、一种活动、...
供应商要账,老板不肯付钱我该怎... 供应商要账,老板不肯付钱我该怎么办就说财务章或法人章丢失正在办理,需要一段时间,让他们耐心等待!
女人想见你,才会发出哪些信号,... 女人想见你,才会发出哪些信号,你都知道吗?1、汪者主动联系你,问你“你有羡孝空吗?” 2、抱怨你和...
壁虎叫声是什么样的? 壁虎叫声是什么样的?壁虎的叫声有很多种,有的类似乌鸦的叫声,有的类似青蛙叫,还有的类似婴儿啼哭。声音...
传奇 攻城是什么意思 传奇 攻城是什么意思攻城 沙巴克是什么意思?怎么功??攻城就是拿沙或者沙战,想攻沙就带组玛头象和1个...
最后的莫西干人林子祥什么时候唱... 最后的莫西干人林子祥什么时候唱的的《最后的莫西干人》是由林子祥演唱的歌曲,发行于**1987年**。
梦中呓语是什么意思 梦中呓语是什么意思梦中呓语是什么意思梦中呓语就是“说梦话”,这样说文雅一点而已。
他自己打骂他自己的父母他不是傻... 他自己打骂他自己的父母他不是傻子呀?不是傻子连傻子都不是。就不是人是狗
大剑普莉希拉为什么那么强 大剑普莉希拉为什么那么强技能和能力强、特殊装备或武器。1、技能和能力强:大剑普莉希拉可能拥有强大的技...