http://ybt.ssoier.cn:8088/problem_show.php?pid=1433
愤怒的牛,经典运用二分法求解的题目。
#include<iostream>
#include<algorithm>
using namespace std;
int m,n;
int a[100005];
bool check(int t){
int temp=a[0]+t,y=1;
for(int i=1;i<n;i++)
{
if(a[i]<temp) continue;
++y;
temp=a[i]+t;
}
return y>=m;
}
int main(){
int i;
cin>>n>>m;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int l=0,r=a[n-1]-a[0];
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
l=mid+1;
else
r=mid-1;
}
cout<<r<<endl;
}
http://ybt.ssoier.cn:8088/problem_show.php?pid=1435
曲线 这种抛物线的题目先减后增,先增后减的二次函数就可以用三分,本来因为函数不确定我还没想明白,但是max(f(x))的整体趋势又不会改变所以他还是可以直接用经典思路就行了
#include<iostream>
#include<iomanip>
using namespace std;
int a[10005],b[10005],c[10005];
int n,m;
int max(int a,int b){
return a>b?a:b;
}
double cal(double x){
double maxx=-0x7fffffff;
for(int i=0;i<n;i++)
maxx=max(maxx,a[i]*x*x+b[i]*x+c[i]);
return maxx;
}
int main(){
int i,j;
int t;
cin>>t;
while(t--){
cin>>n;
for(i=0;i<n;i++) cin>>a[i]>>b[i]>>c[i];
double l=0,r=1000;
while(l+1e-11<r) {
double lmid=l+(r-l)/3;
double rmid=r-(r-l)/3;
if(cal(lmid)<=cal(rmid)) r=rmid;
else l=lmid;
}
cout<<fixed<<setprecision(4)<<cal(l)<<endl;
}
}
http://ybt.ssoier.cn:8088/problem_show.php?pid=1437
扩散这题看了别人的题解才知道不用二分好像简单很多
不用二分:直接用二维数组dp[N][N]表示两个点间的距离,然后列举出来找最大值就行。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int x[N],y[N],fa[N],d[100][100];
int n;
int m,q,ans,p,tot;
int read()
{
int f=1;
char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-')f=-1;
int res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res*f;
}
void write(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)write(x/10);
putchar(x%10+'0');
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
d[i][j]=d[j][i]=abs(x[i]-x[j])+abs(y[i]-y[j]);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
if(k!=i) for(int j=1;j<=n;j++)
if(j!=k&&j!=i)
d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
ans=max(ans,d[i][j]);
write((ans+1)/2);
return 0;
}
二分法:思路就是为了找到一个最大的最小距离,用二分法快速列举所有情况,然后check的条件就是满足所有的点都可以联通起来
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int x[N],y[N],fa[N],d[100][100];
int n;
int m,q,w,ans,p,tot;
int read()
{
int f=1;char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-')f=-1;
int res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res*f;
}
void write(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)write(x/10);
putchar(x%10+'0');
}
int find(int x)
{
if(fa[x]!=x)fa[x]=find(fa[x]);
return fa[x];
}
bool check(int t)
{
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(d[i][j]<=t*2)
{
int fx=find(i),fy=find(j);
if(fx!=fy)fa[fy]=fx;
}
int sum=0;
{
if(fa[i]==i)sum++;
if(sum==2)return false;
}
return true;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
d[i][j]=d[j][i]=abs(x[i]-x[j])+abs(y[i]-y[j]);
int l=0,r=999999999;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))r=mid-1,ans=mid;
else l=mid+1;
}
write(ans);
return 0;
}