http://acm.hdu.edu.cn/showproblem.php?pid=4790
Just Random
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2985 Accepted Submission(s): 906
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.
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).
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
思路:分母很好算,区间长度乘积。分子分为3部分,先把区间分为两部分,一部分是长度p倍数的区间,剩下一部分是余下的不够长度p的区间。
举个栗子,任意一个数字都能在0,1,2中找到一个数字,使他们的和为3的倍数,和也可以是3的倍数加上一个余数。并且2,3,4也符合上面的结论,而且一定能找的一个且仅有一个。
这两个区间的整数部分很好算,重点是求两个余出的区间中匹配数量。
举个栗子。p=8,m=1
2,3,4,5,6(两个余下的区间,L区间)
0,1,2,3,4,5(R区间)
想个办法把区间变成这样
4,5,6
3,4,5(这样就能两两匹配了)
计算方法是:先找能与Lmax(L区间中最大数字)匹配的数字。用x=Lmax-Rmin;看y=x-(p+m)的正负,y正的话说明Lmax太大了多了y个,把L区间的前y大删去,y负的话,说明Rmin太小了,把R区间前y小删去。
然后同理x=Rmax-Lmin;跟上面的完全相反,再删一遍之后就得到了4,5,6和3,4,5一一匹配。
因为p+m可能有多个值,比如m,m+2*p,m+3*p等等。y=x-(p+m)的情况很多,也可能是y=x-(2*p+m);解决方法在代码中有解释。虽然不知道什么是容斥原理,但我还是A了这道题,思路比较难想,但想到就能一遍过。
我比赛时的AC代码:
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cmath>
#include<cstring>
#define LL long long
using namespace std;
LL a1,a2,b1,b2,mod,p,la,lb,fenzi,fenmu,lam,lbm,aa1,aa2,bb1,bb2;
LL hg(LL r,LL rr,LL l,LL ll,LL k)//[r,rr],[l,ll],和为k
{
LL flag1=rr-r+1;//r区间的长度
LL flag2=ll-l+1;//l区间的长度
LL x=ll+r;//ll区间的最大值加上r区间的最小值,跟k比较大小
if(x>k) flag2-=(x-k);//重点是看这里是什么意思,减去后剩下的就是能匹配的
if(x<=k) flag1-=(k-x);
x=rr+l;//同上
if(x>k) flag1-=(x-k);
if(x<=k) flag2-=(k-x);
if(flag1<=0||flag2<=0) return 0;//长度小于0,就不存在
return flag1;
}
int main()
{
int t;
scanf("%d",&t);
int cas=1;
while(t--)
{
scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a1,&a2,&b1,&b2,&mod,&p);
la=a2-a1+1,lb=b2-b1+1;//la为第一个区间的长度,lb为第二个区间的长度
lam=la%mod,lbm=lb%mod;//lam为取余剩的后的长度,lbm同理
fenzi=0,fenmu=la*lb;
fenzi+=lb*(la/mod);//答案的第一部分
fenzi+=lam*(lb/mod);//答案的第二部分
aa1=a1%mod+mod,aa2=aa1+lam-1;//将余下的长度转化成一个区间[aa1,aa2];区间里最大的数字小于mod*3,最小的数字大于等于mod*1.
bb1=b1%mod+mod,bb2=bb1+lbm-1;//同上
//答案的第三部分,求两个余下区间的匹配数量
fenzi+=hg(aa1,aa2,bb1,bb2,mod*2+p);//两个区间最小的两个数和至少为mod*2
fenzi+=hg(aa1,aa2,bb1,bb2,mod*3+p);
fenzi+=hg(aa1,aa2,bb1,bb2,mod*4+p);
fenzi+=hg(aa1,aa2,bb1,bb2,mod*5+p);
fenzi+=hg(aa1,aa2,bb1,bb2,mod*6+p);//两个区间最大的两个数和最多为mod*6
printf("Case #%d: ",cas++);
if(fenzi==0)
printf("0/1\n");
else
printf("%I64d/%I64d\n",fenzi/__gcd(fenzi,fenmu),fenmu/__gcd(fenzi,fenmu));
}
}