题目链接:Click here~~
题意:
有 n 次操作,每次操作是对区间 [a,b] 中以 a 为开头,步长为 c 的点的值加 1。
操作之后,最多出现一个值为奇数的点,找出那个点和那个奇数是多少。
解题思路:
由于区间的范围很大,所以无法暴力。
对于每次操作,相当于给出了一个等差数列,而且可以在 O(1) 的时间求出这个数列中有多少个数。
然后思路是开始统计出一共出现了多少个数,如果是奇数个则有解,反之无解。
然后二分那个奇数点的值 x,统计区间 [1,x] 中出现了多少个数,如果是奇数个,证明答案在 x 左边,如果是偶数个,则证明答案在 x 右边。
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <algorithm>
using namespace std;
const int N = 2e4 + 5;
struct Interval
{
int a,b,c;
void read(){
scanf("%d%d%d",&a,&b,&c);
}
int cnt_all(){
return (b - a) / c + 1;
}
int cnt_less(int x){
if(x < a)
return 0;
else
return (min(b,x) - a) / c + 1;
}
bool has(int x){
return x >= a && x <= b && (x - a) % c == 0;
}
}A[N];
int n;
bool check(int m)
{
long long sum = 0;
for(int i=0;i<n;i++)
sum += A[i].cnt_less(m);
return sum & 1;
}
int main()
{
while(~scanf("%d",&n))
{
long long sum = 0;
for(int i=0;i<n;i++)
{
A[i].read();
sum += A[i].cnt_all();
}
if(sum % 2 == 0)
puts("DC Qiang is unhappy.");
else
{
long long l = 1 , r = INT_MAX;
while(l < r)
{
long long m = l + r >> 1;
if(!check(m))
l = m + 1;
else
r = m;
}
int ans = 0;
for(int i=0;i<n;i++)
if(A[i].has(r))
ans++;
printf("%I64d %d\n",r,ans);
}
}
return 0;
}