【HDU-6333】 Harvest of Apples 【分块】

Problem B. Harvest of Apples
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1060 Accepted Submission(s): 399

Problem Description
There are n apples on a tree, numbered from 1 to n.
Count the number of ways to pick at most m apples.

Input
The first line of the input contains an integer T ( 1 T 105 ) denoting the number of test cases.
Each test case consists of one line with two integers n,m ( 1 m n 105 ) .

Output
For each test case, print an integer representing the number of ways modulo 109+7.

Sample Input

2
5 2
1000 500

Sample Output

16
924129523

Source
2018 Multi-University Training Contest 4

分析:将n分B块,然后可以将n分为两个部分一个部分是 A = (n/B*B, m) ,然后n %B的部分可以由A部分递推得到S(n, m) = 2 * S(n - 1, m) - C(n - 1, m), 就可以将多余部分o(B)时间处理完,所以整体时间复杂度为o(n * B)
代码

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define bug(x)  cout<<"@@  "<<x<<"\n"

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;
const int MAX= (int) 1e5;
const int INF = (int)0x3f3f3f3f;
const int MOD = (int)1e9 + 7;

#include <ext/rope>
using namespace __gnu_cxx;

inline void add(int &a, int b){  a = a + b >= MOD ? a + b - MOD : a + b; }
inline void sub (int &a, int b){ a = a - b < 0 ? a - b + MOD : a - b; }

int fac[N], inv[N];
ll qpow(ll a, ll b, ll c){
    ll s = 1, base = a % c;
    while(b){
        if(b & 1) s = s * base % c;
        b >>= 1;
        base = base * base % c;
    }
    return s;
}
int C(int n, int m){
    if(m > n) return 0;
    if(m == n || m == 0) return 1;
    return fac[n] * 1ll * inv[n - m] % MOD * inv[m] % MOD; 
}
const int B = 333;
int sum[N / B + 1][N], dp[B][B];
void init(){
    fac[0] = 1; 
    for(int i = 1; i <= MAX; i++) fac[i] = fac[i - 1] * 1ll * i % MOD;
    inv[MAX] = qpow(fac[MAX], MOD - 2, MOD);
    for(int i = MAX - 1; ~i; i--) inv[i] = inv[i + 1] * 1ll * (i + 1) % MOD;

    for(int i = B; i <= MAX; i += B){
        int ans = 0;
        for(int j = 0; j <= MAX; j++){
            add(ans, C(i, j));
            sum[i / B][j] = ans; 
        }
    }
    // 0-B的部分 单独取出来
    for(int i = 1; i < B; i++){
        int ans = 0;
        for(int j = 0; j <= i; j++){
            add(ans, C(i, j));
            dp[i][j] = ans;
        }
    }
}

int main(){

    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif

    init();
    int T; scanf("%d", &T);
    while(T--){
        int n, m; scanf("%d%d", &n, &m);
        int ans = 0;
        if(n < B) ans = dp[n][m];
        else if(n % B == 0) ans = sum[n / B][m];
        else {
            add(ans, 2 * sum[n / B][m] % MOD);
            sub(ans, C(n / B * B, m)); // 得到 S(n/B*B +1, m)的值
            for(int i = n / B * B + 2; i <= n; i++){ // 继续遍历到n
                ans = 2 * ans % MOD - C(i - 1, m);
                if(ans < 0) ans += MOD;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37383726/article/details/81353600