HDU 4768 Flyer 二分套二分

题意:

给N组数,每组三个数 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci,表示K个数
A i , A i + C i , A i + 2 ∗ C i , … A i + k ∗ C i A_i, A_i+C_i,A_i+2*C_i,…A_i+k*C_i Ai,Ai+Ci,Ai+2Ci,Ai+kCi
( A i + k ∗ C i < = B i , A i + ( k + 1 ) ∗ C i > B i A_i+k*C_i<=B_i, A_i+(k+1)*C_i>B_i Ai+kCi<=Bi,Ai+(k+1)Ci>Bi).)其实就是一个等差数列,求在这N个数列中出现次数为奇数的那个数和出现的次数,题中数据保证该数只有一个

思路:

因为数据保证该数只有一个,要是存在,那么所有出现的数出现的次数和一定是个奇数。如果和是个偶数,就可以直接输出答案了。否则,我们二分答案,如何check呢?如果出现的数(都小于等于mid)的次数和是个奇数,说明答案在mid的左边,执行R=mid-1;如果是个偶数,说明答案在mid的右边,这时执行L=mid+1。代码中有许多细节要注意!

#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>

using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll MAX_N=2e4+7;
ll N,A[MAX_N],B[MAX_N],C[MAX_N];
ll tmp;
bool check(ll nmd){
	ll i,j,cnt=0;
	tmp=0;
	for(i=1;i<=N;i++){
		ll tmd=min(B[i],nmd);//保证数不能越界,数值最大才B[i]
		if(tmd<A[i])//小于起始值了,跳过
		continue;
		cnt+=((tmd-A[i])/C[i]+1);
	}
	if(cnt&1)
	return 1;
	return 0;
}
int main()
{
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	ll i,j,k;
	while(~scf("%lld",&N)){
		ll cnt=0,L=INF,R=0,mid; 
		for(i=1;i<=N;i++){
			scf("%lld %lld %lld",&A[i],&B[i],&C[i]);
			if(B[i]>=A[i]){
				cnt+=((B[i]-A[i])/C[i]+1);
				R=max(R,B[i]);
				L=min(L,A[i]);				
			} 
		}
		if(!(cnt&1)){
			prf("DC Qiang is unhappy.\n");
			continue;
		}
		ll res,res1;
		while(L<=R){
			mid=L+(R-L)/2;
			if(check(mid)){//左边的区间是奇数 
				res=mid;					
				R=mid-1;
			}
			else{
				L=mid+1;
			}
		}
		//求出现次数
		res1=0;
		for(i=1;i<=N;i++){
			if(res>=A[i]&&res<=B[i]){
				if((res-A[i])%C[i]==0)
				res1++;
			}
		}
		prf("%lld %lld\n",res,res1);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值