HDU 4768 Flyer 二分套二分

题意:

给N组数,每组三个数A_i,B_i,C_i,表示K个数
A_i, A_i+C_i,A_i+2C_i,…A_i+kC_i
(A_i+k*C_i<=B_i, A_i+(k+1)*C_i>B_i).)其实就是一个等差数列,求在这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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43311695/article/details/108564783