hdu 4768

找出手持奇数传单的人及其传单数,如果没有则按要求输出,直接暴力肯定是不行的,通常在暴力情况下不行的时候就得想想如何优化,二分是首先应该想到的,首先可以先根据给定的每个社团的所发传单号满足等差数列,由此可以统计一下总的传单数,为偶数则可以得出不存在奇数传单情况,因为奇数传单有且只存在一个,如果否则需要找出手持奇数传单的,接下来就需要二分了,那么如何进行二分呢?先找出最大编号的同学,那么根据分析可知,中中间开始找传单数的前缀和,如果为奇数则可知该同学编号处于二分的左边,利用等差数列的特点继续二分不断找知道找出该同学就好。这种思路一定要熟悉才行,比赛的时候基础题至少会吧。

#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;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值