Problem B. Harvest of Apples
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1463 Accepted Submission(s): 555
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
题意:计算c(n,0),c(n,1),,,c(n,m);
思路:分块,将1e5分成根号1e5块(333)。采用逆元的方式计算出n为333倍数的所有组合数,在处理出其前缀,另外处理处n<333的所有组合数,这样对于n<333的情况直接处理即可,对于n>=333情况,分为两部分一部分为333的倍数p,另一部分为除以333的余数q,这样就可以转换为在这两部分内分别处理。总时间复杂度为O(333*T)。
参考自:https://blog.csdn.net/zstu_zy/article/details/81334302
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e5+10;
ll dp[335][maxn],C[335][335];
ll inv[maxn],fac[maxn],invf[maxn];
void init()
{
inv[1]=1;
for (int i=2;i<maxn;i++)
inv[i]=((mod-mod/i)*inv[mod%i])%mod;
fac[0] = 1;
for(int i = 1;i<maxn;i++)
fac[i] = (fac[i-1] * (ll)i)%mod;
invf[0] = 1;
for(int i = 1;i<maxn;i++)
invf[i] = (invf[i-1]*inv[i])%mod;
C[0][0] = 1;
for(int i=1;i<335;i++)
{
C[i][0] = 1;
for(int j=1;j<=i;j++)
C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod;
}
dp[0][0] = 1;
for(int i=1;i*333<maxn;i++)
{
for(int j=0;j<=i*333;j++)
{
dp[i][j] = ((fac[i*333]*invf[j])%mod*invf[i*333-j])%mod;
if(j>0)dp[i][j] = (dp[i][j] + dp[i][j-1])%mod;
}
}
}
int main()
{
init();
int t;
int n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int p = n/333,q = n%333;
ll ans = 0;
if(n<=333)
{
for(int i = 0;i <= m;i++)ans = (ans + C[n][i])%mod;
printf("%lld\n",ans);
}
else
{
for(int i =0;i<=min(q,m);i++)
{
ans = (ans + (C[q][i]*dp[p][min(m-i,p*333)])%mod)%mod;
}
printf("%lld\n",ans);
}
}
}