题目链接:点击打开链接
需要注意的点是:
1.如何表示这些票发给了某人(开始我想的是用数组,然后数组下标代表人,数组中存票数,不过这里数据量太大,不可)。
2.通过奇,偶性来知道要找的人在那个区间。
3.如何定义较大的数据变量。
4.二分搜索结束后,想找的人如何表示
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
long long a[200001], b[200001], c[200001];
long long cal(long long mid){//本函数用于判断截止到mid发出去的传单数量
int sum = 0;
for(int i = 0; i < n; i++){//用来求总的发传单的次数
long long x = min(b[i], mid);//x用来表示最左端到mid的距离,但是当b[i]<mid的时候,只算到b[i],就足够了
if(x>=a[i])//需要保证x在a[i]右边
sum += (x-a[i])/c[i] + 1;//求单个社团传单的次数,例如(20-5)/7 = 2,而这里还有计算上5本身也有一张票所以再加1
}
return sum;
}
void solve(){
long long l, r, mid, sum;
l = 0; r = 1LL << 31;//学生总数为1到2^32,1LL是2^64,位运算31后是2^33
while(l < r){
mid = (l + r)/2;
sum = cal(mid);
if(sum%2 == 0) l = mid + 1;//当返回值(从左到中的发出去的票数)为偶数,说明该学生在右边
else r = mid;
}
if(l == 1LL << 31)//找完也没有
printf("DC Qiang is unhappy.\n");
else{
while(cal(r)%2 == 0) r++;//因为r和l交错后循环结束,所以向右寻找合适的r(也可向左寻找合适的l)
cout<<r<<' '<<cal(r)-cal(r-1)<<endl;
}
}
int main(){
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; i++){
scanf("%d%d%d", &a[i], &b[i], &c[i]);
}
solve();
}
return 0;
}