zoukankan      html  css  js  c++  java
  • HDU4790_Just Random

      这个题目我只能说我一看就知道是这么做的,但是由于实现能力略水,Wa了3发。

    题意为给你两个区间[a,b]和[c,d],两个区间分别任取一个数,现在要你求出这个数模p的值为m的概率有多大。

    其实是这么做的,我们需要统计总共有多少种组合情况然后等于就知道分母和分子了。

    但是怎么求种类数呢 ???

    首先我们定义一个函数count(x,y),表示从0-x,0-y随机取两数满足情况的种类数。

    那么最后我们要求的答案ans=count(a,b)-count(a-1,b)-count(a,b-1)+count(a-1,b-1)。

    这是容斥原理,到这里问题就转化为了求函数值呢。

    但是我们的根本的问题还是没有解决。到底怎么求呢?

    我们可以这样考虑,给一个数A,现在问你x%p=m(x不大于A)的种类数有多少?

    显然,如果A%p>=m,答案就是A/p+1,如果A%p<m,答案就是A/p。

    这里自己算一算就知道了。。。

    然后我们等于是由二维优化到了一维,但是还是不够,还有继续优化。

    我们知道取模具有周期性,所以我们可以保证最后我们要求其中一个的范围的不会超过p。

    假设我们从0开始循环枚举第一个i,那么每次i没增加1,其实就是最终的种类数相当于m减1,如果我们看成p个数对应的函数值,那么我们等于是把每一个函数值右移了一位。

    如果你理解了上面,那么恭喜你,可以A掉这个题目了。

    具体来说就是这样的,首先不超过A%p的函数值都为A/p+1,超过的部分为A/p。也就是说,只有两种不同的函数值,而且是连续的。

    接下来我们等于是每次移动一位,然后求某一固定位置的函数值,这样我们发现移动若干位后的函数值才会变化一次,而且总共最多变化两次(因为循环部分的可以直接计算了),所以找出突变点做一次乘法就可以出答案了。

    其实函数移动就是求连续段的函数值啦。。。只是那样好理解一定。

    手滑Wa了若干发。。。。OTL。代码也挺挫的,求见谅。

    哦,对了,是循环移动。 

    #include <iostream>
    #include <cstdio>
    #define ll long long
    using namespace std;
    
    ll a,b,c,d,n,m,p,ans,t,cas=0,G,sum;
    
    ll gcd(ll A,ll B) { return B==0?A:gcd(B,A%B); }
    
    ll count(ll x,ll y)
    {
        if (x<0 || y<0) return 0;
        ll tot=0,flag=y%p,left=(x+1)%p,cur=m,End=(cur-left+1+p)%p;
        ll all=((y%p+1)*(y/p+1)+(p-1-y%p)*(y/p));
        tot=((x+1)/p)*all;  
        if (left==0) return tot;
        if (cur<End && End<=flag)
        {
            tot+=all-(End-cur-1)*(y/p+1);
            return tot;
        }
        if (cur<End && cur>flag)
        {
            tot+=all-(End-cur-1)*(y/p);
            return tot;
        }
        if (cur<End)
        {
            tot+=(cur+1)*(y/p+1)+(p-End)*(y/p);
            return tot;
        }
        if (cur>=End && End>flag)
        {
            tot+=(cur-End+1)*(y/p);
            return tot;
        }
        if (cur>=End && cur<=flag)
        {
            tot+=(cur-End+1)*(y/p+1);
            return tot;
        }
        if (cur>End)
        {
            tot+=(cur-flag)*(y/p)+(flag-End+1)*(y/p+1);
            return tot;
        }
        return tot;
    }
    
    int main()
    {
        scanf("%I64d",&t);
        while (t--)
        {
            scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m);
            ans=count(b,d)-count(a-1,d)-count(b,c-1)+count(a-1,c-1);
            sum=(b-a+1)*(d-c+1);
            if (ans==0)
            {
                printf("Case #%I64d: 0/1
    ",++cas);
                continue;
            }
            G=gcd(ans,sum);
            ans/=G,sum/=G;
            printf("Case #%I64d: %I64d/%I64d
    ",++cas,ans,sum);
        }
        return 0;
    }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    Vue,动画-修改v-前缀
    Vue,动画-使用过度类名实现动画(渐变)
    sqli-labs闯关之21-30关
    sqli-labs闯关之11-20关,第18关有burpsuit的具体使用方法
    sqli-labs闯关之1-10关
    sqli-labs的搭建
    DVWA-SQL注入
    华为NAT配置
    基础过滤工具——ACL控制访问列表(Access Control List)
    DHCP——基于接口地址的池的DHCP
  • 原文地址:https://www.cnblogs.com/lochan/p/3427011.html
Copyright © 2011-2022 走看看