题意:
给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+2∗Ci,…Ai+k∗Ci
(
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+k∗Ci<=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;
}