题意:
有N个社团..有很多的学生..编号从1开始的连续正整数..现在每个社团发传单给其Ai+K*Ci不大于Bi的所有学生发传单...之多可能有一个学生拿了奇数个传单..请求出这个学生的学号以及他拿的传单数.
题解:
由于之多一个学生的传单数位奇数..代表其他的学生都是偶数..代表在只要有解,必定总传单数位奇数..再想..假设该学生在位置x..用num[i]代表i号学生拿到的传单数量..那么sigma(num[1],num[x])为奇数..并且当k>x..所有的sigma(num[1],num[k])都为奇数..而当k<x时..所有的sigma(num[1],num[k])都为偶数..这样就找到了单调关系.用二分法解决...每次暴力的算出该右界的情况下传单总数...值得注意的是A,B可能为0..处理的时候小心..因为就算能发给0号学生.但0号学生是不存在的..不算发了..
Program:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdlib>
#include<stack>
#include<map>
#define MAXN 20005
#define ll long long
#define eps 1e-8
using namespace std;
struct node
{
int A,B,C;
}P[MAXN];
ll check(ll x,int n)
{
ll sum=0,t,A,B,C;
if (x<0) return 0;
for (t=1;t<=n;t++)
{
A=P[t].A,B=P[t].B,C=P[t].C;
if (A>x || A>B) continue;
B=min(B,x);
sum+=(int)((B-A)/(C*1.0))+1;
}
return sum%2;
}
int num(ll x,int n)
{
int i,sum=0;
for (i=1;i<=n;i++)
{
if (P[i].A>x || P[i].B<x || (x-P[i].A)%P[i].C) continue;
sum++;
}
return sum;
}
int main()
{
int i,n,N;
while (~scanf("%d",&n))
{
for (i=1;i<=n;i++)
{
scanf("%d%d%d",&P[i].A,&P[i].B,&P[i].C);
if (!P[i].A) P[i].A+=P[i].C;
}
ll l,r,mid;
l=0,r=1<<30,r*=2;
while (r-l>1)
{
mid=l+r>>1;
if (check(mid,n)) r=mid;
else l=mid;
}
N=num(r,n);
if (N%2==0) printf("DC Qiang is unhappy.\n");
else printf("%I64d %d\n",r,N);
}
return 0;
}