poj3484 Showstopper 二分

来源:互联网 发布:网络恶意诽谤 编辑:程序博客网 时间:2024/06/08 02:25

http://poj.org/problem?id=3484


因为题目说至多存在一个奇数点,所以前缀和的奇偶性一定是

偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶偶奇奇奇奇奇奇奇奇奇奇奇 的样子

等价于我们要找第一个奇数点,二分该点的坐标来判断即可。


至于判断呢需要以O(n)的时间来找出从1到k的一段的点数,具体实现看代码~

输入格式非常坑,小心数据与数据之间有可能有多个空行。

#include <iostream>#include <cstring>#include <cstdlib>#include <cmath>#include <vector>#include <cstdio>#include <algorithm>#define N 500005typedef long long LL;using namespace std;int n ;LL X[N] , Y[N] , Z[N];char str[55];LL cal(LL k){  LL sum = 0 , x;  for (int i = 1 ; i <= n; ++ i)  {    if (k < X[i]) continue;    x = min(k , Y[i]);    sum += (x - X[i]) / Z[i] + 1;  }  return sum;}void work(){  n = 1;  X[n] = 0;  sscanf(str , "%I64d %I64d %I64d" , &X[n] , &Y[n] , &Z[n]);  if (!X[n]) return;  memset(str , 0 , sizeof(str));  while (gets(str) , *str)    ++ n , sscanf(str , "%I64d %I64d %I64d" , &X[n] , &Y[n] , &Z[n]) , memset(str , 0 , sizeof(str));  LL l = 1 , r = 1LL << 33 , m;  while (l < r)  {    m = (l + r) >> 1;    if (cal(m) & 1)      r = m;    else l = m + 1;  }  if (l == 1LL << 33)    puts("no corruption");  else printf("%I64d %I64d\n" , l , (cal(l) - cal(l - 1)));}int main(){  while(gets(str))    work();  return 0;}