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
denoting the number of test cases.
Each test case consists of one line with two integers n,m
.
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;
}