hdu 4970 Just Random(数学:推理)

题意很简单,给出两个区间[a, b], [c, d]

在给出两个整数p, m

问你这两个区间各取一个数字使其和模p为m

这样的数占所有情况的比例


这个题学长说的思路,我敲的代码,真的给我搞的元气大伤!!

因为区间内的数是连续的,所以我们可以推知对于所有情况的集合S

可以把S分为3段,左侧一段从1递增,中间一段保持不变,右侧一段递减至1


接着就一步一步推,处理就好了

还是自己太弱,写了接近4个小时再见


代码如下(完美注释。。。):

#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL unsigned long long
using namespace std;

LL gcd(LL a, LL b) {
    return b ? gcd(b, a%b) : a;
}

int main(void) {

    int T, a, b, c, d, p, m;
    LL l_left, m_left, r_left, tmp;
    LL l_right, m_right, r_right;

    LL l_first, l_last, l_cnt, l_sum;
    LL m_first, m_last, m_cnt, m_sum;
    LL r_first, r_last, r_cnt, r_sum;

    scanf("%d", &T);
    for(int _=1; _<=T; ++_) {
        scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &p, &m);
        l_left = a+c; l_right = a+c+min(b-a, d-c)-1;
        m_left = l_right+1; m_right = b+d-min(b-a, d-c);
        r_left = m_right+1; r_right = b+d;
/*
        printf("左边界: %lld -- %lld\n", l_left, l_right);
        printf("中间边界: %lld -- %lld\n", m_left, m_right);
        printf("右边界: %lld -- %lld\n", r_left, r_right);
        puts("");puts("");puts("");puts("");
*/
        l_first = l_last = -1;

        tmp = l_left+(m-l_left%p);
        if(m >= l_left%p)
            l_first = tmp;//左侧等差数列第一项
        else l_first = tmp+p;
        if(l_first > l_right || l_first < l_left)
            l_first = -1;


        tmp = l_right-(l_right%p-m);
        if(m <= l_right%p)
            l_last = tmp;//左侧等差数列最后一项
        else l_last = tmp-p;
        if(l_last < l_left || l_last > l_right)
            l_last = -1;

        if(l_first==-1 && l_last==-1) {
            l_cnt = 0;
            l_sum = 0;
        } else if(l_first == -1) {
            l_cnt = 1;
            l_sum = l_last-l_left+1;
        } else if(l_last == -1) {
            l_cnt = 1;
            l_sum = l_first-l_left+1;
        } else {
            l_cnt = (l_last-l_first)/p+1;//左侧符合条件的项数
            l_sum = ((l_first-l_left+1) + (l_last-l_left+1))*l_cnt>>1;
        }
/*
        printf("左侧等差数列满足条件边界:%lld -- %lld\n", l_first, l_last);
        printf("左侧的个数和结果:%lld -- %lld\n", l_cnt, l_sum);
        puts("");puts("");puts("");puts("");
*/



        m_first = m_last = -1;

        tmp = m_left+(m-m_left%p);
        if(m >= m_left%p)
            m_first = tmp;
        else m_first = tmp+p;
        if(m_first > m_right || m_first < m_left)
            m_first = -1;

        tmp = m_right-(m_right%p-m);
        if(m <= m_right%p) 
            m_last = tmp;
        else m_last = tmp-p;
        if(m_last < m_left || m_last > m_right)
            m_last = -1;

        if(m_last==-1 && m_first==-1) {
            m_cnt = 0;
            m_sum = 0;
        } else if(m_first == -1) {
            m_cnt = 1;
            m_sum = m_left-l_left+1;
        } else  if(m_last == -1) {
            m_cnt = 1;
            m_sum = m_left-l_left+1;
        } else {
            m_cnt = (m_last-m_first)/p+1;
            m_sum = m_cnt*(m_left-l_left+1);
        }
/*
        printf("中间等差数列满足条件边界:%lld -- %lld\n", m_first, m_last);
        printf("中间的个数和结果:%lld -- %lld\n", m_cnt, m_sum);
        puts("");puts("");puts("");puts("");
*/




        r_first = r_last = -1;
        tmp = r_left+(m-r_left%p);
        if(m >= r_left%p)
            r_first = tmp;
        else r_first = tmp+p;
        if(r_first > r_right || r_first < r_left)
            r_first = -1;

        tmp = r_right-(r_right%p-m);
        if(m <= r_right%p) 
            r_last = tmp;
        else r_last = tmp-p;
        if(r_last < r_left || r_last > r_right)
            r_last = -1;


        if(r_last==-1 && r_first==-1) {
            r_cnt = 0;
            r_sum = 0;
        } else if(r_first==-1 && r_last!=-1) {
            r_cnt = 1;
            r_sum = (r_right-r_last+1);
        } else if(r_last == -1 && r_first!=-1) {
            r_cnt = 1;
            r_sum = (r_right-r_first+1);
        } else {
            r_cnt = (r_last-r_first)/p+1;
            r_sum = r_cnt*((r_right-r_first+1) + (r_right-r_last+1))>>1;
        }
/*        
        printf("右侧等差数列满足条件边界:%lld -- %lld\n", r_first, r_last);
        printf("右侧的个数和结果:%lld -- %lld\n", r_cnt, r_sum);
        puts("");puts("");puts("");puts("");
*/

        LL ans1 = l_sum+m_sum+r_sum;
        LL ans2 = (LL)(b-a+1)*(d-c+1);

        LL g = gcd(ans1, ans2);
        if(g) {
            ans1 /= g;
            ans2 /= g;
        }

        if(ans1 == 0) 
            ans2 = 1;

        printf("Case #%d: ", _);
        cout << ans1 << "/" << ans2 << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值