码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4790 Just Random

时间:2015-07-16 11:57:27      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:区域赛   hdu   概率   

题目链接:Just Random


题面:

Just Random

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


Problem Description
  Coach Pang and Uncle Yang both love numbers. Every morning they play a game with number together. In each game the following will be done:
  1. Coach Pang randomly choose a integer x in [a, b] with equal probability.
  2. Uncle Yang randomly choose a integer y in [c, d] with equal probability.
  3. If (x + y) mod p = m, they will go out and have a nice day together.
  4. Otherwise, they will do homework that day.
  For given a, b, c, d, p and m, Coach Pang wants to know the probability that they will go out.
 

Input
  The first line of the input contains an integer T denoting the number of test cases.
  For each test case, there is one line containing six integers a, b, c, d, p and m(0 <= a <= b <= 109, 0 <=c <= d <= 109, 0 <= m < p <= 109).
 

Output
  For each test case output a single line "Case #x: y". x is the case number and y is a fraction with numerator and denominator separated by a slash (‘/‘) as the probability that they will go out. The fraction should be presented in the simplest form (with the smallest denominator), but always with a denominator (even if it is the unit).
 

Sample Input
4 0 5 0 5 3 0 0 999999 0 999999 1000000 0 0 3 0 3 8 7 3 3 4 4 7 0
 

Sample Output
Case #1: 1/3 Case #2: 1/1000000 Case #3: 0/1 Case #4: 1/1
 

Source
2013 Asia Chengdu Regional Contest

解题:画几组样例后发现,左边是以1递增的,中间是等长的,右边是以1递减的。找到区间范围内第一个符合%p=m的点,然后直接根据区间长度求出答案。不过,因为p的区间范围过大,需要分类讨论。较小的时候可以循环去找,较大的时候,需计算出第一个可以的点,然后再算。(代码这么乱七八糟,估计过两天自己都看不懂了!)

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <cmath>
#include <cstdlib>
#include <set>
#include <algorithm>
#include <string>
#include <iomanip>
#define LL long long
using namespace std;
LL min(LL a,LL b)
{
	if(a<=b)return a;
	else return b;
}
LL max(LL a,LL b)
{
	if(a>=b)return a;
	else return b;
}
LL gcd(LL a,LL b)
{
	if(a==0)return b;
	return gcd(b%a,a);
}
int main()
{
	int t;
	cin>>t;
    LL a,b,c,d,m,p,ans,x,start,num,line,tmp,bound,lim,total,gcdd;
	bool flag;
	for(int cas=1;cas<=t;cas++)
	{
		flag=false;
		ans=0;
		cout<<"Case #"<<cas<<": ";
        cin>>a>>b>>c>>d>>p>>m;
		line=min(b-a,d-c)+(a+c);
		//cout<<"line: "<<line<<endl;
		tmp=min(b-a,d-c);
		bound=max((b-a),(d-c))+1;
		//cout<<"tmp: "<<tmp<<endl;
		x=a+c;
		if(p<10000)
		{
		  for(int i=1;i<=tmp;i++)
		  {
             if(x%p==m)
		     {
			     start=i;
			     //cout<<"p: "<<p<<endl;
			     //cout<<"x: "<<x<<endl;
			     //cout<<"start: "<<start<<endl;
			     flag=true;
			     break;
		     }
		     x++;
	 	  }
		  if(flag)
		  {
		    num=(line-1-x)/p+1;
		    //cout<<"num: "<<num<<endl;
		    ans+=(start+(start+(num-1)*p))*num/2;
		    //cout<<"* "<<ans<<endl;
		    flag=false;
	      }
				//cout<<"line: "<<line<<endl;
		  for(int i=tmp+1,x=line;i<=bound;i++)
		  {
			  if(x%p==m)
			  {
				  start=i;
				  flag=true;
				  break;
			  }
			  x++;
		  }
		  if(flag)
		  {
			  num=(bound-start)/p+1;
			  ans+=num*min(b-a+1,d-c+1);
			  //cout<<"** "<<ans<<endl;
			  flag=false;
		  }
		  lim=(b-a)+(d-c)+1;
		  for(int i=tmp,x=bound+(a+c);i>=1;i--)
		  {
             if(x%p==m)
		     {
			    //cout<<"x: "<<x<<endl;
                start=i;
			    //cout<<"start: "<<start<<endl;
			    flag=true;
			    break;
		     }
			 x++;
		  }
		  if(flag)
		  {
			  num=(start)/p+1;
			  //cout<<"num: "<<num<<endl;
			  //cout<<"start: "<<start<<endl;
			  ans+=(start+(start-(num-1)*p))*num/2;
		  }
		 }
		else
		{
		   flag=false;
           start=m;
           while(1)
		   {
			   if(start>=x)
			   {
				   if(start<line)
				     flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(line-1-start)/p+1;
               tmp=start-x+1;
               ans+=(tmp+tmp+(num-1)*p)*num/2;
			   flag=false;
		   }
		   start=(line/p)*p+m;
		   lim=line+abs((b-a)-(d-c));
           while(1)
		   {
			   if(start>=line)
			   {
				   if(start<=lim)
				      flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(lim-start)/p+1;
			   tmp=min((b-a),(d-c))+1;
			   ans+=num*tmp;
			   flag=false;
		   }
		   start=((lim+1)/p)*p+m;
		   bound=a+c+(b-a)+(d-c);
		   while(1)
		   {
			   if(start>lim)
			   {
				   if(start<=bound)
					   flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(bound-start)/p+1;
			   tmp=min((b-a),(d-c))+1-(start-lim);
			   ans+=(tmp+(tmp-(num-1)*p))*num/2;
		   }
		}
          total=(b-a+1)*(d-c+1);
          gcdd=gcd(ans,total);
          cout<<ans/gcdd<<"/"<<total/gcdd<<endl;
	}
	return 0;
}

跟进:
    仔细想了一下,可以改进一下,p不用分类,反正每次都能直接得到第一个位置,将以上代码p较大的情况下,第一次的起始位置改成直接(a+c)/p*p+m就可以不用分类了。

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <cmath>
#include <cstdlib>
#include <set>
#include <algorithm>
#include <string>
#include <iomanip>
#define LL long long
using namespace std;
LL min(LL a,LL b)
{
	if(a<=b)return a;
	else return b;
}
LL max(LL a,LL b)
{
	if(a>=b)return a;
	else return b;
}
LL gcd(LL a,LL b)
{
	if(a==0)return b;
	return gcd(b%a,a);
}
int main()
{
	int t;
	cin>>t;
    LL a,b,c,d,m,p,ans,x,start,num,line,tmp,bound,lim,total,gcdd;
	bool flag;
	for(int cas=1;cas<=t;cas++)
	{
		flag=false;
		ans=0;
		cout<<"Case #"<<cas<<": ";
        cin>>a>>b>>c>>d>>p>>m;
		line=min(b-a,d-c)+(a+c);
		//cout<<"line: "<<line<<endl;
		tmp=min(b-a,d-c);
		bound=max((b-a),(d-c))+1;
		//cout<<"tmp: "<<tmp<<endl;
		x=a+c;
		flag=false;
        start=(a+c)/p*p+m;
           while(1)
		   {
			   if(start>=x)
			   {
				   if(start<line)
				     flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(line-1-start)/p+1;
               tmp=start-x+1;
               ans+=(tmp+tmp+(num-1)*p)*num/2;
			   flag=false;
		   }
		   start=(line/p)*p+m;
		   lim=line+abs((b-a)-(d-c));
           while(1)
		   {
			   if(start>=line)
			   {
				   if(start<=lim)
				      flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(lim-start)/p+1;
			   tmp=min((b-a),(d-c))+1;
			   ans+=num*tmp;
			   flag=false;
		   }
		   start=((lim+1)/p)*p+m;
		   bound=a+c+(b-a)+(d-c);
		   while(1)
		   {
			   if(start>lim)
			   {
				   if(start<=bound)
					   flag=true;
				   break;
			   }
			   start+=p;
		   }
		   if(flag)
		   {
			   num=(bound-start)/p+1;
			   tmp=min((b-a),(d-c))+1-(start-lim);
			   ans+=(tmp+(tmp-(num-1)*p))*num/2;
		   }
          total=(b-a+1)*(d-c+1);
          gcdd=gcd(ans,total);
          cout<<ans/gcdd<<"/"<<total/gcdd<<endl;
	}
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 4790 Just Random

标签:区域赛   hdu   概率   

原文地址:http://blog.csdn.net/david_jett/article/details/46907521

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!