http://acm.hdu.edu.cn/showproblem.php?pid=4790
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 <= x <= b,c <= y<= d,求满足 (x+y)%p==m 的(x,y)的个数。
题解:(x+y)%p==m, (x+y)==p*K+m。假设x 固定,那么对于区间【c,d】,满足条件的最大的Kmax为,Kmax=floor( (x + d-m) / p)。 floor为向下取整。
满足条件的最小的Kmin为:Kmin=ceil( (x+c-m)/p )。ceil为向上取整。所以当x固定是,满足条件的个数为: Kmax-Kmin+1。((x+d-m)<0或(x+c-m)<0时同样满足该式,因为
m<p)。 因为 a<=x<=b ,所以容易求出 sum(Kmax)和 sum(Kmin)。那么答案就sum(Kmax)-sum(Kmin)+(b-a+1)。(具体见代码)
#include<iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<string> #include<math.h> #define nn 510 #define inff 0x3fffffff using namespace std; typedef __int64 LL; LL a,b,c,d,p,m; LL jie(LL x) //当x==d-m时求 Kmax 的和,当x==c-m+p-1 时求 Kmin的和 (因为向上取整可以转化为向下取整,所以只写了一个求和的函数) { LL z=floor(1.0*(b+x)/p); LL zz=floor(1.0*(a+x)/p); if(zz==z) return z*(b-a+1); LL re=0 ; LL ix=(z-1)*p-x; ix+=p; re+=z*(b-ix+1); ix=(zz+1)*p-x; ix--; re+=zz*(ix-a+1); LL f1=zz+1,f2=z -1; if(f1<=f2) re+=(f1+f2)*(f2-f1+1)/2*p; return re; } LL solve() { return jie(d-m)-jie(c-m+p-1)+b-a+1; } LL gcd(LL x,LL y) { if(y==0) return x; return gcd(y,x%y); } int main() { int t,cas=1; scanf("%d",&t); while(t--) { scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m); LL fz=solve(); LL fm=(b-a+1)*(d-c+1); LL ix=gcd(fz,fm); printf("Case #%d: ",cas++); printf("%I64d/%I64d\n",fz/ix,fm/ix); } return 0; }