HDU 4790 找规律

题意是说区间[a,b]取一个数x,[c,d]取一个数y,求(x+y)%p==m的概率

可知,分母是(b-a+1)*(d-c+1),接下来就是找分子的个数了,即一共有多少个满足性质的整数对(x,y)使得(x+y)%p == m


一、区间减法的性质

       可以转化为求[0,b][0,d]中取整数对(x,y)有多少对

       即

              [a,b][c,d] = [0,b][0,d] - [0,a-1][0,d] - [0,b][0,d-1] + [0,a-1][0,c-1];


二、求[0,a][0,b]中的整数对满足(x+y)%p = m

       观察发现 x      y

                     0      m

                     1      m-1

                     2      m-2

                     ...     ...

                     m      0         x+y=m

             -----------------------华丽丽的小分割线---------

                    m+1    p-1     x+y=p+m

                    m+2    p-2

                      ..        ...

                    p-1     m+1      

            假设左边有k1个满足x%p==0,右边有k2个满足y%p==m,那么对这一行就是k1*k2。但是,但是这种情况下的分类讨论似乎很难做

            于是继续拆分[0,a]拆成[0,k1*p-1]和[k1*p,a];[0,b]拆成[0,k2*p-1]和[k2*p,b];

            分类讨论

             1. [0,k1*p-1][0,k2*p-1]

                       一一对应的关系 p*k1*k2

             2.[0,k1*p-1][k2*p,b]

                      把[k2*p,b]当成[0,b%p],那么对于每一个y在[0,b%p]都有k1个对应的x 即(b%p+1)*k1

             3.[k1*p,a][0,k2*p-1]

                       同上     (a%p+1)*k2

             4.[k1*p,a][k2*p,b]

                      又要分类了,观察上面的规律

                       4.1   a%p>=m  b%p>=m      m+1+{ m+p-(b%m) <= x <= a%p }

                       4.2   a%p>=m  b%p<m        b%p+1

                       4.3   a%p<m    b%p>=m      a%p+1

                       4.4   a%p<m    b%p<m        {m-b%p <= x <= a%p}



#include <stdio.h>
#include <string.h>
#include <queue>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdlib.h>
using namespace std;
typedef unsigned long long ll;
const int maxn = 100005;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}

ll solve(int a,int b,int p,int m){
    if(a < 0 || b < 0)return 0;
    //ll ans = (a/p+a%p)*(b/p+b%p);
   // printf("%d %d %d %d\n",a,b,p,m);
    int sa = a/p;
    int sb = b/p;
    int ma = a%p;
    int mb = b%p;
    ll ans = (ll)p*sa*sb+(ll)sa*(mb+1)+(ll)sb*(ma+1);
    //printf("%lld\n",ans);
    if(ma >= m && mb >= m){
        ans += 1 + m + max(ma-(m+p-mb)+1,0);
    }
    else if(ma >= m && mb < m){
        ans += mb+1;
    }
    else if(ma < m && mb >= m){
        ans += ma+1;
    }
    else if(ma < m && mb < m){
        ans += max(0,ma-(m-mb)+1);
    }
    //printf("%lld\n",ans);
    return ans;
}
//0 0 10 10 3 2
int main(){
    int a,b,c,d,p,m;
   // freopen("out","r",stdin);
   // freopen("out1","w",stdout);
    int T;
    cin >> T;
    //T = 100;
    int cas = 1;
    while(T --){
        cin >> a >> b >> c >> d >> p >> m;
        //printf("%d %d %d %d %d %d\n",a,b,c,d,p,m);
        ll ansx = solve(b,d,p,m)-solve(a-1,d,p,m)-solve(b,c-1,p,m)+solve(a-1,c-1,p,m);
        ll ansy = (ll)(b-a+1)*(d-c+1);
        ll _gcd = gcd(ansx,ansy);
        printf("Case #%d: ",cas++);
        printf("%I64d/%I64d\n",ansx/_gcd,ansy/_gcd);
        //cout << ans << endl;
    }
}

/*
int main(){
    ll cnt = 0;
    freopen("out","w",stdout);
    cout << 1884960 << endl;
    for(int a=0;a<=15;a++){
        for(int b=a;b<=15;b++){
            for(int c=10;c<=20;c++){
                for(int d=c;d<=20;d++){
                    for(int p=1;p<=20;p++){
                        for(int m=0;m<p;m++){
                            //cnt ++;
                            printf("%d %d %d %d %d %d\n",a,b,c,d,p,m);
                        }
                    }
                }
            }
        }
    }
    //cout << cnt << endl;
}
*/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值