解析
因为至多有一个单数
假设其位置为k,1-i的累加和为s[i]
则s[1]-s[k-1]全是偶数
s[k]-s[max]全是奇数
答案呈单调性,可以用二分算法
check函数(计算前缀和)也很容易用O(n)写出:
long long check(int x){
long long tot=0;
for(int i=1;i<=n;i++){
if(p[i].b<=x){
tot += (p[i].b-p[i].a)/p[i].m+1;
}
else if(p[i].a>x) continue;
else{
tot += (x-p[i].a)/p[i].m+1;
}
}
return tot;
}
(时间复杂度应该可以更优,但这样够了,大脑就不想动了。。。)
两个地方要加1,因为排头有一个,之后的个数这是长度除间隔的地板除法
然后二分枚举位置判断奇偶即可
PS:不开longlong见祖宗
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<string>
#include<queue>
#include<vector>
using namespace std;
const int M=1e9;
long long n,t;
long long mx=0;
struct node{
long long a,b,m;
}p[200500];
long long check(int x){
long long tot=0;
for(int i=1;i<=n;i++){
if(p[i].b<=x){
tot += (p[i].b-p[i].a)/p[i].m+1;
}
else if(p[i].a>x) continue;
else{
tot += (x-p[i].a)/p[i].m+1;
}
}
return tot;
}
int main(){
scanf("%lld",&t);
for(int k=1;k<=t;k++){
mx=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld"
,&p[i].a,&p[i].b,&p[i].m);
mx=max(mx,p[i].b);
}
long long st=0,ed=mx+1;
while(st<ed){
long long mid=(st+ed) >> 1;
if(check(mid)%2==1) ed=mid;
else st=mid+1;
}
if(st==mx+1){
//返回mx+1,说明全是偶数,无懈可击
printf("Poor QIN Teng:( \n");
continue;
}
printf("%lld %lld\n",st,check(st)
-check(st-1));
}
return 0;
}