HDU 多校第四场Problem B. Harvest of Apples 莫队算法

B

HDU 多校第四场Problem B. Harvest of Apples 莫队算法_第1张图片

S(n,m) = S(n,m-1) + C(n,m)
S(n,m) = 2 * S(n-1,m) - C (n-1,m)
这个式子可由杨辉三角得出:上面一行的相邻两个元素相加得下面的元素,那么下面元素的和就是上面一行和的2倍减去上一行最后一个元素,因为它对下面一行只贡献了一次。
由上两个式子可得:
S(n,m) = S(n,m+1) + C(n,m+1)
S(n+1,m) = 2 * S(n,m) - C(n,m)
那么知道S(n,m),并且预处理逆元与阶乘就可O(1)求出。

#include 
#define LL long long 
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 3e5+66;
const int MOD = 1e9+7;
const int MAX = 1e5;
int b[AX];
int fac[AX];
int inv[AX];
int res[AX];
struct Node{
    int l , r ;
    int id ; 
/*  bool friend operator < ( const Node &x , const Node &y ){
        return ( b[x.l] == b[y.l] ? x.r < y.r : b[x.l] < b[y.l] );
    }*/
}s[AX];

bool cmp( Node a , Node b ){
    return a.r < b.r;
}

int quick( int a , int b ){
    int ans = 1 ;
    while( b ){
        if( b & 1 ){
            ans = ( 1LL * ans * a ) % MOD;
        }
        b >>= 1 ;
        a = ( 1LL * a * a ) % MOD;
    }
    return ans ;
}

int C(int a, int b){
    return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}

std::vector v[AX];

int main(){
    int T;
    fac[0] = 1; 
    for( int i = 1 ; i <= MAX ; i++ ){
        fac[i] = 1LL * fac[i-1] * i % MOD ;
    }
    inv[MAX] = quick( fac[MAX] , MOD - 2 );
    for( int i = MAX - 1 ; ~i ; i-- ){
        inv[i] = 1LL * inv[i+1] * ( i + 1 ) % MOD; 
    }

    scanf("%d",&T);
    int len = sqrt(MAX);
    for( int i = 1  ; i <= MAX ; i++ ){
        b[i] = ( i - 1 ) / len + 1 ;
    }
    for( int i = 1 ; i <= T ; i ++ ){
        scanf("%d%d",&s[i].r,&s[i].l);
        s[i].id = i ;
        v[b[s[i].l]].push_back(s[i]);
    }
    for( int i = 1 ; i <= b[MAX] ; i++ ){
        if( !v[i].size() ) continue;
        sort( v[i].begin() , v[i].end() , cmp );
        int ans = 0 , r = v[i][0].r , l = -1 ;
        for( int j = 0 ; j < v[i].size() ; j++ ){
            while( r < v[i][j].r ) ans = ( 0LL + ans + ans + MOD - C( r ++ , l ) ) % MOD; 
            while( r > v[i][j].r ) ans = ( ( ans + C( --r , l ) ) % MOD * inv[2] ) % MOD;

            while( l < v[i][j].l ) ans = ( ans + C( r , ++l ) ) % MOD;
            while( l > v[i][j].l ) ans = ( ans + MOD - C( r , l-- ) ) % MOD ;
            res[v[i][j].id] = ans ; 
        }
    }
    for( int i = 1 ; i <= T ; i++ ) printf("%d\n",res[i]);
        return 0 ;
}


两种分块方法,刚开始下面的一直wa,改了后也A了,放一下。

#include 
#define LL long long 
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 3e5+66;
const int MOD = 1e9+7;
const int MAX = 1e5;
int b[AX];
int fac[AX];
int inv[AX];
int res[AX];
struct Node{
    int l , r ;
    int id ; 
    bool friend operator < ( const Node &x , const Node &y ){
        return ( b[x.l] == b[y.l] ? x.r < y.r : b[x.l] < b[y.l] );
    }
}s[AX];

int quick( int a , int b ){
    int ans = 1 ;
    while( b ){
        if( b & 1 ){
            ans = ( 1LL * ans * a ) % MOD;
        }
        b >>= 1 ;
        a = ( 1LL * a * a ) % MOD;
    }
    return ans ;
}

int C(int a, int b){
    return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}

int main(){
    int T;
    fac[0] = 1; 
    for( int i = 1 ; i <= MAX ; i++ ){
        fac[i] = 1LL * fac[i-1] * i % MOD ;
    }
    inv[MAX] = quick( fac[MAX] , MOD - 2 );
    for( int i = MAX - 1 ; ~i ; i-- ){
        inv[i] = 1LL * inv[i+1] * ( i + 1 ) % MOD; 
    }

    scanf("%d",&T);
    int len = sqrt(MAX);
    for( int i = 1  ; i <= MAX ; i++ ){
        b[i] = ( i - 1 ) / len + 1 ;
    }
    for( int i = 1 ; i <= T ; i ++ ){
        scanf("%d%d",&s[i].r,&s[i].l);
        s[i].id = i ;
    }
    LL ans = 1LL;
    int l = 0 , r = 0 ;

    sort( s + 1 , s + 1 + T );
    for( int j = 1 ; j <= T ; j++ ){
        while( r < s[j].r ) ans = ( 0LL + ans + ans + MOD - C( r ++ , l ) ) % MOD; 
        while( r > s[j].r ) ans = ( ( ans + C( --r , l ) ) % MOD * inv[2] ) % MOD;

        while( l < s[j].l ) ans = ( ans + C( r , ++l ) ) % MOD;
        while( l > s[j].l ) ans = ( ans + MOD - C( r , l-- ) ) % MOD ;
        res[s[j].id] = ans ; 
    }

    for( int i = 1 ; i <= T ; i++ ) printf("%d\n",res[i]);
        return 0 ;
}


你可能感兴趣的:(莫队算法,分块算法)