您的位置:首页 > 其它

2013 ACM/ICPC Asia Regional Changchun Online Problem J & hdu4768 Flyer(二分)

2013-09-28 22:01 399 查看
题目请戳这里

题目大意:给n个三元组(ai,bi,ci),那么对于y = ci*x + ai(ai <= y <= bi,x >= 0),求所有三元组产生的y中,出现次数为奇数的数以及出现次数。数据保证最多存在一个数出现奇数次。如果没有数出现奇数次,输出一句话。

题目分析:从出现奇数次作为突破口。首先对于某个三元组(ai,bi,ci),yi = ci * x + ai,yi <= bi,那么可以确定这个三元组产生了(bi - ai)/ci + 1个数,那么统计所有三元组产生的数的总和,如果为偶数,那么一定不存在出现奇数次的数,直接输出那句话。如果是奇数,那么我们只需要找到这个数即可。

这个数可能很大,给每个整数开个计算器显然不可能。对所有三元组出现的数一一枚举也不可取,考虑到出现奇数次的只有一个数,那么我们可以在1~2^32范围内二分,寻找奇数区间,不断缩小范围,最后缩成一个点,那就是ans。

trick:1:二分的时候用__int64,会爆int;

2:ci可以为0!!当ci=0的时候,ai = bi;

详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
const int N = 20005;
const int M = 10000005;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const double PI = acos(-1.0);
typedef __int64 ll;
struct node
{
ll a,b,c,num;
}p
;
ll n,maxx;

ll fuck(ll x)
{
int ret = 0;
for(ll i = 1;i <= n;i ++)
{
if(p[i].c == 0)
{
if(x >= p[i].a)
ret ++;
continue;
}
if(x <= p[i].b && x >= p[i].a)
{
ret += ((x - p[i].a)/p[i].c + 1);
}
else if(x > p[i].b)
ret += p[i].num;
}
return ret;
}

void gao()
{
ll l,r,mid;
l = 1;r = maxx;
ll tmp,tp;
ll ans;
ll tl = 0;
while(l <= r)
{
mid = (l + r)>>1;
tmp = fuck(mid);
if((tmp - tl) & 1)
r = mid - 1,ans = mid;
else
l = mid + 1,tl = tmp;
}
printf("%d %d\n",ans,fuck(ans) - tl);
}

int main()
{
ll i;
while(scanf("%d",&n) != EOF)
{
ll sum = 0;
maxx = 0;
for(i = 1;i <= n;i ++)
{
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
if(p[i].c == 0)
p[i].num = 1;
else
{
p[i].num = (p[i].b - p[i].a)/p[i].c;
p[i].num ++;
}
sum += p[i].num;
if(maxx < p[i].b)
maxx = p[i].b;
}
if((sum&1) == 0)
{
puts("DC Qiang is unhappy.");
continue;
}
gao();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分
相关文章推荐