1. 程式人生 > >HDU 4790 找規律

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;
}
*/