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 <= 10 9, 0 <=c <= d <= 10 9, 0 <= m < p <= 10 9).
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
设f(a,b)为(0<=x<=a,0<=y<=b)时的答案,由容斥定理可得
ans=f(b,d)-f(a-1,d)+f(a-1,c-1)-f(b,c-1)(前面为[a,b],[0,d],后面部分为-[a,b],[0,c-1]。)
首先是对p取余,那么区间的数都可以看成对p取余之后的数,那么两个区间就可以化为若干个[0,p-1]整区间和一个[0,?]的部分区间。问题就转为求取值范围分别为[0,p-1],[0,?]时解的个数,写写就可以知道不管m取多少,在[0,p-1]的任何一个数都可以找到一个也在[0,p-1]的数符合要求。也就是说两个[0,p-1]区间内,有p个答案。这里就可以分类求。
1.整区间:分别算出整区间的个数(numx,numy),那么整区间之间的贡献就是numx*numy*p。
2.部分区间:假设分别为[0,modx]、[0,mody],首先在每个整区间肯定都能找到相对应的数,所以贡献为(modx+1)*numy+(mody+1)*numx。剩下的就是[0,modx],[0,mody]这两个部分区间之间的贡献了。我们现在要找的是x+y=kp+m,因为0<=x,y<=p-1,0<=x+y<=2*p-2,所以k只能取0或1,即找x+y=m和x+y=p+m。我们可以只取x,然后在[0,mody]区间内找y=m-x和p+m-x即可。那么需要的y的取值范围就是[m-modx,m]和[p+m-modx,p+m],我们可以用mody分别与m和p+m取个最小值,然后再减去不需要(取不到)的部分即m-modx+1和p+m-modx+1(+1是因为m-modx和p+m-modx这两边界值需要取到。)
(参考博客:https://www.cnblogs.com/naturepengchen/articles/4081232.html)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a,b,c,d,p,m;
ll get(ll x,ll y)
{
if(x<0||y<0) return 0;
ll numx,numy,modx,mody,num1,num2;
ll ans=0;
numx=x/p,modx=x%p;//整数区间个数,部分区间[0,modx]
numy=y/p,mody=y%p;
//cout<<numx<<" "<<modx<<endl;
//cout<<numy<<" "<<mody<<endl;
//和整数区间有关的所有贡献
ans=numx*numy*p+(modx+1)*numy+(mody+1)*numx;
//和部分区间之间的贡献
num1=max(0LL,min(mody,m)-max(m-modx,0LL)+1);
num2=max(0LL,min(mody,p+m)-max(p+m-modx,0LL)+1);
ans+=(num1+num2);
return ans;
}
int main(void)
{
int t,tt=0;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&p,&m);
ll ans=get(b,d)-get(a-1,d)+get(a-1,c-1)-get(b,c-1);
ll down=(b-a+1)*(d-c+1);
ll g=__gcd(ans,down);
ans/=g; down/=g;
printf("Case #%d: %lld/%lld\n",++tt,ans,down);
}
return 0;
}