HDU 4790 Just Random

3 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4790
题意: 给出a,b,c,d,p,m;
在区间[a,b]之间随机选择出x,在区间[c,d]之间随机选择出y,求出现(x+y)%p==m的概率。答案用分数表现出来。
分析: 做完后神奇的发现其他人的方法跟我有些 ,, 很大的差别。貌似别人直接推的规律…
我的方法是 就
  既然是分数 ,总方案数 就是分母 肯定是 (b-a+1)*(d-c+1) 接下来求满足要求的x和y
初步想法是
  把区间的每个数 都mod p,就可以知道 区间内 取模出来得到结果一样的数每种有多少。
然后对于第一个区间的每一个数x,求出第二个区间的y的个数让(x+y)%p==m
这个处理后每个数都是< p的。
但是这样p还是很大,所以我就把相同的一些数放在一个区间内处理,最后就是对于每个小区间求出对应的对面区间的 次数。
举个例子吧,比如对于区间[4,35] ,p=10。
我处理出来的区间就是[4,9]有1个,[0,9]有2个,[0,5]有1个
然后我的小区间就是 [0,4] ,[4,5], [5,9]. 对于每个区间[L,R],如果有区间 [Li,Ri] 满足Li<=L<=R<=Ri,那么这个区间的数量就可以被加进去,然后就是各种细节处理。 对应所在的另一个区间是[p+m-R,p+m-L]。
大致想法就这样。

接下来是代码,随便看看。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct qujian
{
    ll L,R,num;
} e[5],f[5];

void add(qujian q[],ll a,ll b,ll c,ll &pos)
{
    q[pos++]=(qujian)
    {
        a,b,c
    };
}
ll work(ll L,ll R,qujian q[],ll pos)
{
    if(L>R) return 0;
    ll te=0;
    for(ll i=0; i<pos; i++)
    {
        if(q[i].L<=L&&q[i].R>=R)
            te+=q[i].num;
    }
    return te;
}
int main()
{
//    freopen("1.in","r",stdin);
//    freopen("2.out","w",stdout);
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        set<ll>s;
        ll hx=0,hx1=0;
        ll a,b,c,d,p,m;
        cin>>a>>b>>c>>d>>p>>m;
        printf("Case #%d: ",cas++);
        if(p==1)
        {
            printf("1/1\n");
            continue;
        }
        ll fz=0,fm;
        fm=b-a+1;
        fm*=d-c+1;
        ll aa=a%p;
        ll bb=b%p;
        s.insert(0);
        if(aa)
        {
            a-=aa;
            add(e,0,aa-1,-1,hx);
            s.insert(aa-1);
            s.insert((p+m-aa+1)%p);
        }
        b-=bb;
        if(bb)
            add(e,1,bb,1,hx),s.insert(bb),s.insert((p+m-bb)%p),s.insert(1),s.insert((p+m-1)%p);
        add(e,0,p-1,(b-a)/p,hx);
        add(e,0,0,1,hx);
        s.insert(p-1);

        a=c;
        b=d;
        aa=a%p;
        bb=b%p;
        if(aa)
        {
            a-=aa;
            add(f,0,aa-1,-1,hx1);
            s.insert(aa-1);
            s.insert((p+m-aa+1)%p);
        }
        b-=bb;
        if(bb)
            add(f,1,bb,1,hx1),s.insert(bb),s.insert((p+m-bb)%p),s.insert(1),s.insert((p+m-1)%p);
        add(f,0,p-1,(b-a)/p,hx1);
        add(f,0,0,1,hx1);


        set<ll>::iterator it=s.begin();
        it++;
        ll pre=0;
        fz+=work(0,0,e,hx)*work(m,m,f,hx1);
        for(; it!=s.end(); it++)
        {
            ll id=*it;
            ll te=0,te1=0;
            id--;
            ll L=pre+1,R=id;//[L,R]是小区间
            if(L>R)
                goto TAR;
            if(L>m)
            {
                ll len=R-L+1;
                fz+=work(L,R,e,hx)*work(p+m-R,p+m-L,f,hx1)*len;
            }
            else if(R<m)
            {
                ll len=R-L+1;
                fz+=work(L,R,e,hx)*work(m-R,m-L,f,hx1)*len;
            }
            else
            {
                fz+=work(L,m-1,e,hx)*work(1,m-L,f,hx1)*(m-L);
                fz+=work(m,m,e,hx)*work(0,0,f,hx1);
                if(m<R)
                fz+=work(m+1,R,e,hx)*work(p+m-R-1,p-1,f,hx1)*(R-m);
            }
TAR:
            id++;
            fz+=work(id,id,e,hx)*work((p+m-(id))%p,(p+m-(id))%p,f,hx1);
            pre=id;
        }
        if(fz==0)
            fm=1;
        else
        {
            ll g=__gcd(fz,fm);
            fz/=g;
            fm/=g;
        }
        printf("%I64d/%I64d\n",fz,fm);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值