找出手持奇数传单的人及其传单数,如果没有则按要求输出,直接暴力肯定是不行的,通常在暴力情况下不行的时候就得想想如何优化,二分是首先应该想到的,首先可以先根据给定的每个社团的所发传单号满足等差数列,由此可以统计一下总的传单数,为偶数则可以得出不存在奇数传单情况,因为奇数传单有且只存在一个,如果否则需要找出手持奇数传单的,接下来就需要二分了,那么如何进行二分呢?先找出最大编号的同学,那么根据分析可知,中中间开始找传单数的前缀和,如果为奇数则可知该同学编号处于二分的左边,利用等差数列的特点继续二分不断找知道找出该同学就好。这种思路一定要熟悉才行,比赛的时候基础题至少会吧。
#include<cstdio>
using namespace std;
long long min(long long a,long long b){
return a<b?a:b;
}
long long max(long long a,long long b){
return a>b?a:b;
}
const int maxn = 20005;
long long a[maxn],b[maxn],c[maxn];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
long long cnt=0;
long long MAX=0;
long long MIN=0x3f3f3f3f;
for(int i=1;i<=n;i++){
scanf("%I64d %I64d %I64d",&a[i],&b[i],&c[i]);
MAX=max(MAX,b[i]);
MIN=min(MIN,a[i]);
cnt+=(b[i]-a[i])/c[i]+1;
}
if(cnt%2==0)printf("DC Qiang is unhappy.\n");
else{
long long mid = (MAX+MIN)/2;
long long R=MAX;
long long L=MIN;
while(L<R){
cnt=0;
for(int i=1;i<=n;i++){
if(mid>=a[i])cnt+=(min(mid,b[i])-a[i])/c[i]+1;
}
if(cnt%2==0)L=mid+1;
else R=mid;
mid=(R+L)/2;
}
long long sum=0;
for(int i=1;i<=n;i++){
if(R>=a[i]&&R<=b[i]&&(R-a[i])%c[i]==0)sum++;
}
printf("%I64d %I64d\n",R,sum);
}
}
return 0;
}