题目链接:
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;
}
}