http://acm.hdu.edu.cn/showproblem.php?pid=4790
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.
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).
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
Case #1: 1/3 Case #2: 1/1000000 Case #3: 0/1 Case #4: 1/1
解题思路:
说实话自己真不会写,看题解也是不知所云。正好去年参加现场赛的学长昨天从百度实习回来了,经他一点播,奋斗了几个小时终于写出来了,瞬间感觉对数论的简单处理又上升了一个等级。
我们先把区间[a,b] [c,d]变为[a+p-m,b+p-m]和[c,d],这样一来题目就变成了求在区间[a+p-m,b+p-m]和[c,d]内各取一个数,有多少取法可以满足(x+y)%p==0,求所占的比例。
我们够着一个平行四边形枚举出所有的情况数;
a+c a+c+1 a+c+2 ..................a+d
a+c+1 a+c+2 a+c+3 ........a+d a+d+1
a+c+2 a+c+3 a+d a+d+1 a+d+2
....................
...................
b+c b+c+1 ...............................................b+d;
上面大致形成一个斜的矩阵。
使用b+c 和 a+d两条竖线,就可以分成三部分。前后两部分个数是等差数列,中间个数是相等的。
根据a+d和b+c的大小关系分两种情况讨论。给定两个例子:我的电脑画图本事不是很好,手写一个了
ac
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
// #define debug
using namespace std;
typedef long long LL;
LL gcd(LL x,LL y)
{
if(y==0)
return x;
return gcd(y,x%y);
}
LL a,b,c,d,p,m;
int main()
{
int T,tt=0;
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m);
LL y=(b-a+1)*(d-c+1);
a+=p-m;///转化为模p为0
b+=p-m;
#ifdef debug
printf("a b c d:%I64d %I64d %I64d %I64d\n",a,b,c,d);
#endif // debug
LL ans=0;
/**情况1: ________
\_______\
**/
if(c+b<=a+d)
{
///左半部分
LL cnt_start=a+c+(p-(a+c)%p)%p;
LL cnt_end=b+c-1-(b+c-1)%p;
LL a1=(p-(a+c)%p)%p+1;
LL n=(cnt_end-cnt_start)/p+1;
ans+=a1*n+p*n*(n-1)/2;
///右半部分
cnt_end=b+d-(b+d)%p;
cnt_start=a+d+(p-(d+a)%p)%p;
a1=(b+d)%p+1;
n=(cnt_end-cnt_start)/p+1;
ans+=a1*n+p*n*(n-1)/2;
/// 中间部分
cnt_end=a+d-1-(a+d-1)%p;
cnt_start=b+c+(p-(b+c)%p)%p;
if(cnt_start>cnt_end)
n=0;
else
n=(cnt_end-cnt_start)/p+1;
a1=b-a+1;
ans+=a1*n;
}
/**情况2:__
\ \
\ \
\ \
\ \
\_\
**/
else
{
///左半部分
LL cnt_start=a+c+(p-(a+c)%p)%p;
LL cnt_end=a+d-(a+d)%p;
LL a1=(p-(a+c)%p)%p+1;
LL n=(cnt_end-cnt_start)/p+1;
ans+=a1*n+p*n*(n-1)/2;
///右半部分
cnt_start=b+c+(p-(b+c)%p)%p;
cnt_end=b+d-(d+b)%p;
a1=(b+d)%p+1;
n=(cnt_end-cnt_start)/p+1;
ans+=a1*n+p*n*(n-1)/2;
/// 中间部分
cnt_start=a+d+1+(p-(a+d+1)%p)%p;
cnt_end=b+c-1-(b+c-1)%p;
if(cnt_start>cnt_end)
n=0;
else
n=(cnt_end-cnt_start)/p+1;
a1=d-c+1;
ans+=a1*n;
#ifdef debug
LL cnt=a1*n+p*n*(n-1)/2;
printf("%I64d ???? %I64d\n",cnt_start,cnt_end);
printf("%I64d %I64d %I64d=cnt\n",a1,n,cnt);
#endif // debug
}
printf("Case #%d: %I64d/%I64d\n",++tt,ans/gcd(y,ans),y/gcd(y,ans));
}
return 0;
}