HDU-4790-Just Random(数学)

本文解析了HDU-4790-JustRandom问题,该问题要求计算两个区间内随机选取的两个数之和模P等于M的概率。通过观察规律和运用等差数列求和公式,文章提供了详细的解题思路和AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU-4790-Just Random(数学)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4790

题意:

  • 先输入一个 T T ,代表有 T 组数据
  • 然后输入 a a , b , c c , d , p p , m

问:在区间 [a,b] [ a , b ] [c,d] [ c , d ] 中分别挑出一个数 x x , y ,满足 (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

解题思路:

找规律 + 等差数列求和公式
等差数列求和公式:

formula

我们自己举几组数据看看,所有的数从小到大排列就会发现每一个相同数的个数它是一个 :

[先上升(等差数列) + 然后平 + 后下降(等差数列) ]

的这么一个规律,而且”平”这一段区间的左右端点分别是 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值