HDU-4790-Just Random(数学)
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4790
题意:
- 先输入一个 T T ,代表有 组数据
- 然后输入 a a , , c c , , p p ,
问:在区间 [a,b] [ a , b ] 和 [c,d] [ c , d ] 中分别挑出一个数 x x , ,满足 (x+y)%p=m ( x + y ) % p = m 的概率为多少?(最简表示)
数据范围:
- 0<=a<=b<=109 0 <= a <= b <= 10 9
- 0<=c<=d<=109 0 <= c <= d <= 10 9
- 0<=m<p<=109 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
解题思路:
找规律 + 等差数列求和公式
等差数列求和公式:
我们自己举几组数据看看,所有的数从小到大排列就会发现每一个相同数的个数它是一个 :
[先上升(等差数列) + 然后平 + 后下降(等差数列) ]
的这么一个规律,而且”平”这一段区间的左右端点分别是 min(a+d,b+c) m i n ( a + d , b + c ) , max(a+d,b+c) m a x ( a + d , b + c )
如:
[1,2] [1,10] p = 3, m = 2
20
2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 //个数是: 1 2 2 2 2 2 2 2 2 2 1 左右端点:3,11
2 -1 -1 -1 -1 5 5 -1 -1 -1 -1 8 8 -1 -1 -1 -1 11 11 -1 //满足条件输出本身,不满足输出 -1
[3,5] [7,9] p = 4, m = 2
9
10 11 11 12 12 12 13 13 14 //个数是: 1 2 3 2 1 左右端点: 12,12
10 -1 -1 -1 -1 -1 -1 -1 14
[1,5] [5,10] p = 5, m = 2
30
6 7 7 8 8 8 9 9 9 9 10 10 10 10 10 11 11 11 11 11 12 12 12 12 13 13 13 14 14 15
-1 7 7 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 12 12 12 12 -1 -1 -1 -1 -1 -1
[1,3] [4,9] p = 3, m = 1
18
5 6 6 7 7 7 8 8 8 9 9 9 10 10 10 11 11 12
-1 -1 -1 7 7 7 -1 -1 -1 -1 -1 -1 10 10 10 -1 -1 -1
[6,11] [7,10] p = 4, m = 2
24
13 14 14 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 20 20 21
-1 14 14 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 18 18 18 18 -1 -1 -1 -1 -1 -1
[1,5] [2,7] p = 2, m = 1
30
3 4 4 5 5 5 6 6 6 6 7 7 7 7 7 8 8 8 8 8 9 9 9 9 10 10 10 11 11 12
3 -1 -1 5 5 5 -1 -1 -1 -1 7 7 7 7 7 -1 -1 -1 -1 -1 9 9 9 9 -1 -1 -1 11 11 -1
知道这个规律了,我们就可以分为三部分分别求出在每一部分满足条件的数的个数.
AC代码:
/********************************************
*Author* : dwh
*Created Time* : 2018年07月12日 星期四 10时54分14秒
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
#define lookln(x) cout << #x << "=" << x << endl
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7fffffff;
inline void OPEN(string s){
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
LL a,b,c,d,p,m,x,y,z;
LL GCD(LL x,LL y){
if(y == 0LL) return x;
return GCD(y,x % y);
}
LL Get(LL l){
LL k = l % p;
if(k > m) k = p - k + m + l;
else k = m - k + l;
return k;
}
LL Solve_left(LL l,LL r){
LL sum = 0LL,k;
x = (r - l + 1LL) * (r - l + 2LL) / 2LL;
k = Get(l);
//printf("k = %lld\n",k);
if(k <= r){
LL all = (r - k) / p + 1LL;
LL a1 = k - l + 1LL;
sum = all * a1 + all * (all - 1LL) / 2LL * p;
}
//printf("%lld\n",sum);
return sum;
}
LL Solve_mid(LL l,LL r){
LL sum = 0LL,k;
y = (b - a + 1LL) * (d - c + 1LL) - 2LL * x;
k = Get(l);
//printf("k = %lld\n",k);
if(k <= r){
sum = ((r - k) / p + 1LL) * (y / (r - l + 1LL));
}
//printf("%lld\n",sum);
return sum;
}
LL Solve_right(LL l,LL r){
//printf("%lld %lld\n",l,r);
LL sum = 0LL,k;
z = x;
k = Get(l);
//printf("k = %lld\n",k);
if(k <= r){
LL ll = a + d,rr = b + c;
if(ll > rr) swap(ll,rr);
LL all = (r - k) / p + 1LL;
LL a1 = (y / (rr - ll + 1LL)) - (k - rr);
//printf("all = %lld a1 = %lld\n",all,a1);
sum = all * a1 + all * (all - 1LL) / 2LL * (-p);
}
//printf("%lld\n",sum);
return sum;
}
void Check(LL sum){
LL all = 0LL;
for(LL i = a;i <= b;i++){
for(LL j = c;j <= d;j++){
if((i + j) % p == m) all++;
}
}
printf("Check all = %lld, sum = %lld\n",all,sum);
}
int main(){
int t,tot = 0;
scanf("%d",&t);
while(t--){
LL sum = 0LL;
scanf("%lld %lld %lld %lld %lld %lld",&a,&b,&c,&d,&p,&m);
LL l = b + c, r = a + d;
if(l > r) swap(l,r);
sum += Solve_left(a + c,l - 1LL);
sum += Solve_mid(l,r);
sum += Solve_right(r + 1LL,b + d);
LL cnt = GCD(sum,(b - a + 1LL) * (d - c + 1LL));
printf("Case #%d: ",++tot);
printf("%lld/%lld\n",sum / cnt,(b - a + 1LL) * (d - c + 1LL) / cnt);
//Check(sum);
}
return 0;
}