题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4768
题目大意:
有n个学生组织发传单,每个学生组织包括三个数A,B,C,三个数表示该组织只发传单给第A+ K*C位学生(A+K*C < B),一共有2^31位学生,其中最多有一位学生是“unlucky”的,找出这名学生的序号及他收到的传单数,否则输出“DC Qiang is unhappy.”。
思路分析:
题目保证最多有一位学生“unlucky”,即最多有一位学生收到奇数张传单,其他 学生都受到偶数张传单,那么:若总传单数为偶数,无“unlucky”学生,否则寻找这位学生(这意味着这位学生一定存在);
为了提高效率,二分区间来寻找这位学生,这位学生一定在(l, r)区间内,只要不断二分枚举mid,计算出0~mid收到的传单数t,如果t为偶数,那么这位同学一定在区间右侧,否则在区间左侧,直到找到这位学生,然后算出他收到的传单数即可。
题目代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAX = 20010; struct Node{ ll A; ll B; ll C; }node[MAX]; bool solve(ll end, int n){ ll ans = 0; for(int i = 0 ; i < n; i++){ if(end >= node[i].A){ ans += ((min(end, node[i].B) - node[i].A)/node[i].C + 1); } } return ans%2; } int main(){ int n; ll N = 1; for(int i = 1;i <= 31; i++){ N *= 2; } while(scanf("%d", &n) != EOF){ for(int i = 0; i < n; i++){ scanf("%lld %lld %lld", &node[i].A, &node[i].B, &node[i].C); } if(!solve(N, n)){ cout<<"DC Qiang is unhappy."<<endl; continue; } ll l, r, mid; l = 0; r = N; ll ans1 = 0; while(l <= r){ mid = (l + r)/2; bool cnt = solve(mid, n); if(cnt){ r = mid - 1; ans1 = mid; } else{ l = mid + 1; } } ll ans2 = 0; for(int i = 0; i < n; i++){ if(node[i].B >= ans1 && ans1 >= node[i].A && (ans1 - node[i].A)%node[i].C == 0){ //cout<<i<<endl; ans2++; } } cout<<ans1<<" "<<ans2<<endl; } }