二分答案法
求可行解的最大值或最小值问题
1.确定答案的最大值和最小值
2.判断二分所得值是否满足条件
3.可行解必须具有单调性(当k可行时,k+1可行或者k-1可行)
每次都要确保right和left有一个被改变。
模板:
//可行解最大值问题
int l=minn,r=maxn;
int ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
问题:
Description
还记得我们新生赛上的这题Averyboy的筷子这题吗?众所周知,Averyboy是一个非常的男孩,既然是一个非常的男孩,那么他就会有许多奇葩的爱好。比如收藏筷子。现在美美旸有n双筷子,编号为1-n,同一双筷子编号相同,美美旸把这些筷子放成一排。现在美美旸对av-boy说,如果你能解决我给你出的一个问题,这些筷子都归你。美美旸的问题是:把这些筷子通过一些操作,使得最后这些筷子是同一双的一定相连。每次的操作是,你可以从这2n支筷子中任意取出一支,剩下的筷子自动合并在一起,然后把这支筷子插入任意一个位置,包括两端。(操作次数无限制。)为了刁难av-boy,美美旸故意定了一个条件,每次只能取出编号大于等于x的筷子。现在你的问题是找出最大的x(1 <= x <= n),使得av-boy一定能顺利拿到筷子。
Input
第一行一个数T,表示测试数据的组数.
接下来T组测试数据。(T <= 5)
每组测试数据的一行为一个数正整数n,代表美美旸的n双筷子。
接下来有2n个数,代表这n双筷子的起始位置。(1<= n <= 100000)Output
每组测试数据输出一个数,表示最大的x,使得av-boy能够拿到美美旸的筷子。
Sample Input
3 2 1 2 1 2 3 1 3 1 2 2 3 4 1 1 2 2 3 3 4 4
Sample Output
2 3 4
#include
#include
using namespace std;
typedef long long ll;
#define MAXN 200010
ll a[MAXN];
ll N;
bool judge(int x)
{
ll b[MAXN];
memset(b,0,sizeof b);
int p=0;
for(int i=1;i<=2*N;i++)
{
if(a[i]>=x)
continue;
if(!b[a[i]])
{
b[a[i]]=++p;
}
else
{
if(b[a[i]]!=p)
{
//cout<>T;
while(T--)
{
cin>>N;
for(ll i=1;i<=2*N;i++)
cin>>a[i];
ll l=1,r=N;
ll ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
cout<
Description
为了检验你上午有没有好好听我讲课,于是有了这题。现在有N种物品,每一种物品有一个基础价值a[i],当买k件物品时,第i件物品的最终价值为a[i] + k * i,现在给你S元,你最多能买多少件物品.
Input
第一行为一个正整数T,代表测试数据的组数(T <= 5)
接下来T组测试数据,每组测试数据第一行为两个整数N, S,分别代表物品的总数和给你的S元(N <= 1e5, S <= 1e18)
接下来一行N个正整数,代表N种物品的基础价值a[i](0 <= a[i] <= 1e6)
Output
对于每组测试数据,输出一个整数,代表你最多能买到多少个物品,如果一件物品也买不起,输出0
Sample Input
2 3 21 1 1 1 3 20 1 1 1
Sample Output
3 2
HINT
第一组测试样例,如果买三件物品一共花费1 + 1 * 3 + 1 + 2 * 3 + 1 + 3 * 3 = 21刚好等于S,所以最多买三件物品。第二组测试数据当然是只能买两件物品啊
#include
#include
using namespace std;
typedef long long ll;
#define MAXN 100010
ll a[MAXN];
ll b[MAXN];
ll N;
ll s;
bool judge(int x)
{
for(ll i=1;i<=N;i++)
{
b[i] = a[i] + i * x;
}
sort(b+1,b+N+1);
ll sum = 0;
for(ll i=1;i<=x;i++)
{
sum+=b[i];
}
if(sum<=s)
{
return true;
}
else return false;
}
int main()
{
ll T;
cin>>T;
while(T--)
{
cin>>N>>s;
for(ll i=1;i<=N;i++)
cin>>a[i];
ll l=1,r=N;
ll ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
cout<
众所周知,averyboy是一个非常男孩。天外天给你他一个问题。问题如下:给你一个长度为N的序列a[1]~a[N]和一个整数sum,我们称一个区间为averyboynb区间,当且仅当这个区间的所有数的和不超过sum。现在你需要找出一个区间和最大的averyboynb区间。
Input
第一行一个整数T,代表测试数据的组数(T <= 5)
接下来T组测试数据。
每组测试数据的第一行为两个数N, sum(N <= 1e5, sum <= 1e18)分别代表序列的长度和上述的sum。
接下来一行N个整数代表序列a[i](1 <= a[i] <= 1e6)Output
对于每组测试数据,输出一个整数,代表区间和最大的averyboynb区间的区间和,如果不存在averyboynb区间直接输出averyboynb.
Sample Input
3 3 4 1 2 3 3 6 2 2 3 3 1 2 2 2
Sample Output
3 5 averyboynb
#include
using namespace std; typedef long long ll; ll s; #define MAXN 100010 ll a[MAXN]; ll Sum[MAXN]; long long f[MAXN]; int main() { ios_base::sync_with_stdio(0); int T; cin>>T; while(T--) { int N; cin>>N>>s; Sum[0]=0; for(int i=1;i<=N;i++) { cin>>a[i]; Sum[i]=Sum[i-1]+a[i]; f[i]=s+Sum[i-1]; } ll ans=-1; for(int i=1;i<=N;i++) { int l=i,r=N; while(l<=r) { int mid=(l+r)/2; if(Sum[mid]<=f[i]) { l=mid+1; ans=max(Sum[mid]-Sum[i-1],ans); } else { r=mid-1; } } } if(ans==-1) cout<<"averyboynb"<
Description
美旸旸现在在腾讯实习。他每工作一天,公司就会给他发一天的工资,但是,当天的工资不一定要当天领,可以等到下次领的时候一起领,但是每次领工资时,之前所有没有领的工资必须这次都领完。现在给你美旸旸工作N天的工资a[1]~a[N],然后给你一个整数M,代表美旸旸一共要领M次工资(不能多也不能少)并且最后一定要把N天的工资领完,毕竟都是美旸旸赚的血汗钱。也就是第N天他是一定要领工资的。(不然就领不完工资了。。。)。现在问题是让你帮美旸旸选择一种领工资的方案,使得这M次领的工资的最大值最小,毕竟美旸旸是一个低调的人,他不想一次领太多钱。你能帮助他吗?
Input
第一行一个整数T(T <= 5)代表测试数据的组数
接下来T组测试数据。
每组测试数据的第一行包括两个整数N, M其含义如上(1 <=N <= 1e5, 1 <= M <= N)
接下来一行N个整数,代表美旸旸每天的工资a[i](1 <= a[i] <= 1e5)
Output
对于每组测试数据输出一个整数,代表所有领工资方案中,领的工资最大值最小的那一种方案的最大值。
Sample Input
1 7 5 100 400 300 100 500 101 400
Sample Output
500
HINT
第一次领第一天和第二天的工资,一共100 + 400 = 500,第二次领第三天和第四天的工资,一共300 + 100 = 400,第三次领第五天的工资,一共500,第四次领第六天的工资,一共101,第五次领第七天的工资,一共400.所以这五次领的工资的 最大值为500.在这种方案下,最大值(500)比其他方案的最大值要小。
#include
#include
#define MAX 1000010
using namespace std;
int a[MAX];
int n,m;
bool judge(int x)
{
int t=0,sum=0;
for(int i=1;i<=n;i++)
{
sum+=a[i];
if(sum>x)
{
sum=a[i];
t++;
}
if(t==m)
return false;
}
return true;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int Max=0,total=0,ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
Max=max(Max,a[i]);
total+=a[i];
}
int l=Max,r=total;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<