标签:之间 开始 style 代码 运用 ati problem names 解决
二分题目中通常有暗示:
最大值最小/最小值最大 (在最之间取平衡点)
最靠近某个值(类似)
最小的能满足条件的代价
***寻找题目中具备的单调性,运用二分解决问题
聪明的质检员 https://www.luogu.org/problemnew/show/ P1314
二分+前缀和(通常区间求值)
通过判断呢,W越大,sum越小,单调性具备。
看了题解,发现min1的初始值设定过小
#include<iostream> #include<algorithm> #include<cstring> using namespace std; #define ll long long struct stone{ ll w,v; }st[200001]; ll n,m,s,min1=0x3f3f3f3f3f3f3f3f,max1=-1,mi=0x3f3f3f3f3f3f3f3f,sumw[200001],sumv[200010]; struct ma{ ll l,r; }q[200001]; int main() { cin>>n>>m>>s; for(int i=1;i<=n;i++) cin>>st[i].w>>st[i].v,mi=min(mi,st[i].w),max1=max(max1,st[i].w); for(int i=1;i<=m;i++) { ll l,r; cin>>q[i].l>>q[i].r; } ll left=mi-1,right=max1,mid; while(left<=right) 二分,列举W可能取值 { mid=(left+right)/2;
memset(sumv,0,sizeof(sumv)),memset(sumw,0,sizeof(sumw)); 注意初始化 for(int i=1;i<=n;i++)前缀和计算w的个数 if(st[i].w>=mid) sumw[i]=sumw[i-1]+1,sumv[i]=sumv[i-1]+st[i].v; else sumw[i]=sumw[i-1],sumv[i]=sumv[i-1]; ll sum=0; for(int i=1;i<=m;i++) sum+=(sumw[q[i].r]-sumw[q[i].l-1])*(sumv[q[i].r]-sumv[q[i].l-1]); //q【i】.l 值也在区间内 min1=min(min1,abs(sum-s)); if(sum>s) left=mid+1; sum>s,可知,W过小,需要变大 else right=mid-1; } cout<<min1; return 0; }
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define maxn 50010 long long sum[maxn],n,cont,m; bool check(long long x) { long long s=0;cont=0; for(int i=1;i<=n+1;i++) if(sum[i]-s<x) cont++;else s=sum[i];//大佬写的一个代码 return cont>m; } int main() { long long l,ans; cin>>l>>n>>m; for(int i=1;i<=n;i++) cin>>sum[i]; long long left=1,right=l; sum[n+1]=l; while(left<=right){ long long mid=(left+right)/2; if(check(mid)) right=mid-1;else ans=mid,left=mid+1;//mid是当前可行解,需要记录下来 } cout<<ans<<endl; return 0; }
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> using namespace std; #define pre 0.6180339887498949 #define maxn 50000 long long length[maxn]; long long rig,lef,mid,n,min1,min2; double mi,mx; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>length[i]; sort(length+1,length+n+1); for(int i=1;i<=n;i++) { long long len=length[i]; lef=1;rig=n; while(lef<=rig) { mid=(lef+rig)/2; mi=(double)length[mid]/(double)len; if(fabs(mx-pre)>fabs(mi-pre)) mx=mi,min1=i,min2=mid;//刚开始将这段放到二分外面,wa。应该是在循环外面少考虑些情况。 if(mi>pre) rig=mid-1;//通过对比,刚开始受之前做的一道题误导,外加自己记串了,刚开始是通过比较与黄金分割的差距,少考虑些情况 else lef=mid+1; } } cout<<min(length[min1],length[min2])<<endl; cout<<max(length[min1],length[min2]); return 0; }
标签:之间 开始 style 代码 运用 ati problem names 解决
原文地址:https://www.cnblogs.com/Showend/p/12339719.html