[ACM]Flyer(长春网络赛1010)

Flyer

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1140    Accepted Submission(s): 397


Problem Description
The new semester begins! Different kinds of student societies are all trying to advertise themselves, by giving flyers to the students for introducing the society. However, due to the fund shortage, the flyers of a society can only be distributed to a part of the students. There are too many, too many students in our university, labeled from 1 to 2^32. And there are totally N student societies, where the i-th society will deliver flyers to the students with label A_i, A_i+C_i,A_i+2*C_i,…A_i+k*C_i (A_i+k*C_i<=B_i, A_i+(k+1)*C_i>B_i). We call a student "unlucky" if he/she gets odd pieces of flyers. Unfortunately, not everyone is lucky. Yet, no worries; there is at most one student who is unlucky. Could you help us find out who the unfortunate dude (if any) is? So that we can comfort him by treating him to a big meal!
 


 

Input
There are multiple test cases. For each test case, the first line contains a number N (0 < N <= 20000) indicating the number of societies. Then for each of the following N lines, there are three non-negative integers A_i, B_i, C_i (smaller than 2^31, A_i <= B_i) as stated above. Your program should proceed to the end of the file.
 


 

Output
For each test case, if there is no unlucky student, print "DC Qiang is unhappy." (excluding the quotation mark), in a single line. Otherwise print two integers, i.e., the label of the unlucky student and the number of flyers he/she gets, in a single line.
 


 

Sample Input
2 1 10 1 2 10 1 4 5 20 7 6 14 3 5 9 1 7 21 12
 


 

Sample Output
1 1 8 1
 


 

Source
 


 

Recommend
liuyiding

 

解题思路:

本题的大致意思是共有2的32次方个学生,编号1到2的32次方,有N个社团(0<N<=20000)每个社团对应着三个数值,ai,bi,ci,学生数目众多,每个社团不能每个学生都发到传单,所以按照一定规律(等差数列)来发给特定编号的学生,每个社团所发的学生编号为 ai,   ai+1*ci,   ai+2*ci,   ai+3*ci,    ai+4*ci,........直到(ai+k*ci<=bi,   ai+(k+1)*ci>bi)为止,最多有一个学生他所得到的传单总数为奇数,要求输出这个学生的编号和他所得的传单数。一开始的思路是开 2的32次方大的数组来保存每个学生发到的传单数,然后遍历一遍,遇到奇数则输出编号和值得大小,但是数组太大了,开不出来,所以不能以学生的数量开数组,而是以社团的数量考虑,下面代码中是把每个社团都设为结构体,保存着ai,bi,ci。编写cal(int x)函数,用来求前x个学生所得到的传单总数,因为奇数+偶数=奇数,偶数+偶数一定等于偶数,所以如果算出cal(int x)为奇数,那么那个得到传单数为奇数的同学一定在前x个学生里面,但不一定编号就是x,采用二分的方法,将这个传单数位奇数的同学的编号精确到1。

代码:

#include <iostream>
#include <algorithm>
using namespace std;

int N;

struct tuan
{
    long long ai;
    long long bi;
    long long ci;
}shetuan[20005];//社团结构体

long long cal(long long mid)
{
    long long sum=0;
    for(int i=1;i<=N;i++)
    {
        long long limit=min(shetuan[i].bi,mid);//bi是限制范围,最大编号不能超过它
        if(limit>=shetuan[i].ai)
        {
            sum+=(limit-shetuan[i].ai)/shetuan[i].ci+1;//计算前Mid个学生得到的第i个社团的传单总数
        }
    }//计算前mid个学生得到的所有社团的传单的总数
    return sum;
}

int main()
{

    int i;
    while(cin>>N)
    {
        for(i=1;i<=N;++i)
            cin>>shetuan[i].ai>>shetuan[i].bi>>shetuan[i].ci;

    long long l=1,r=1LL<<31;//注意这里要写为1LL<<31  不能只写为1<<31

    while(l<r)
    {
        long long mid=(l+r)/2;
        if(cal(mid)%2==1)
            r=mid;
        else
            l=mid+1;
    }//二分,把得到传单为奇数的学生的编号精确到1,即l
    if(l==1LL<<31)
        cout<<"DC Qiang is unhappy."<<endl;//没有得到传单数为奇数的学生
    else
        cout<<l<<" "<<cal(l)-cal(l-1)<<endl;//前l个学生得到的传单总数-前l-1个学生得到的传单总数得到第l个学生(编号为l)得到的传单总数(奇数)
    }
    return 0;
}


 

运行截图:

posted @ 2013-10-15 12:22  同学少年  阅读(233)  评论(0编辑  收藏  举报