蓝桥学苑系列第二课,二分。查漏补缺吧。
-
lower_bound 查询(a,a+n)中>=x的第一个数的下标(从0开始)
-
upper_bound 查询(a,a+n)中>x的第一个数的下标(从0开始)
题目1链接:http://hihocoder.com/problemset/problem/1357?sid=1347312
题解:二分枚举时间t,并且对每个t用函数来判断。
注意点在于题目说每秒回复伤害,其实就是给防护罩加血,加到满血为止。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 100005;
#define eps 1e-8
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
ll n,m,k,a[maxn],b[maxn];
bool crash(int t)
{
int cnt=m,tot=0;
for(int i=0;i<n;i++)
{
if(a[i]>=cnt)
{
tot++;
cnt = m;
}
else {
cnt = min(m,cnt-a[i]+t);
}
}
if(tot>=k)
return false;
return true;
}
int main()
{
int cnt = 0;
cin>>n>>m>>k;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(a[i]>=m)
cnt++;
}
if(cnt>=k) //如果能一炮打穿的炮弹数大于保护层数,直接输出-1
{
cout<<-1<<endl;
return 0;
}
int l = 1,r = m;
int ans;
while(l<=r)
{
int mid = (l+r)>>1;
if(crash(mid)) //只有在满足条件的情况下记录ans,最后一个被记录的ans一定为最优解
{
r = mid-1; //如果当前解已经是最优解,那么r会缩到比当前解小,但是缩了以后必然不满足条件
ans = mid;
}
else
l = mid+1;
}
cout<<ans<<endl;
return 0;
}
题目2链接:http://hihocoder.com/problemset/problem/1692?sid=1347393
题意:略
题解:
此题有毒。
我们已知一个质数为a,一个(0,1)的数为x,那么质数a中所有小于等于x的子分数的个数恰好为x*a
这一点并不是很难证明,假想质数a为5,x为3/5,那么小于等于其的分数自然而然有3个(1/5,2/5,3/5)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
#define eps 1e-8
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
ll n,k,p[maxn];
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>p[i];
double l = 0.0, r = 1.0;
while(true)
{
ll cnt=0,best_fz = -1,best_fm=-1;
double mid = (l+r)/2;
for(int i=0;i<n;i++)
{
ll x = p[i]*mid;
cnt += x;
if(best_fz==-1) { //如果没有存储最优值,就赋当前值
best_fz = x;
best_fm = p[i];
}
if(best_fz*p[i]<best_fm*x) { // x/p[i]是p[i]中<=x的最大的一个数,对于i∈[0,n),我们要取的是之前这些中的最大的,否则就不满足条件(正好为第k小)
best_fz = x;
best_fm = p[i];
}
}
if(cnt == k) {
cout<<best_fz<<"/"<<best_fm<<endl;
return 0;
}
else if(cnt<k) l = mid;
else r = mid;
}
return 0;
}
题目3链接:http://codeforces.com/contest/1011/problem/C
题意:就是有一艘飞船飞来飞去的,问满足条件最少要带多少油。
题解:这题学弟是递推做出来的,当然也可以用二分来做。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
#define eps 1e-8
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
int n,m;
double a[maxn],b[maxn],mid;
int main()
{
read(n),read(m);
for(int i=0;i<n;i++)
scanf("%lf",&a[i]);
for(int i=0;i<n;i++)
scanf("%lf",&b[i]);
double l=1,r=1e9+10;
int cnt = 0;
while(true)
{
cnt++;
if(cnt>=500)
break;
mid = (l+r)/2;
double w = m+mid;
w -= w/a[0];
for(int i=1;i<n;i++)
{
w -= w/a[i];
w -= w/b[i];
}
w -= w/b[0];
if(abs(w-m)<eps){
printf("%.10lf",mid);
return 0;
}
else if(w<m) l = mid;
else r = mid;
}
cout<<-1<<endl;
return 0;
}