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
题意 求出sigma(C(n,0)-C(n,m))
解题思路:
比赛时想出了解法,但写了两个小时,比赛时没交上去。。。 难受。
T,n,m为 1e5
总状态数高达1e10 显然不能暴力枚举
又因为T为1e5。 思考是否可以通过提高询问复杂度来降低枚举状态的复杂度。
考虑 , n为定值的情况。
我们可以取一些定点,然后每次查询就通过离要查询状态最近的点出发。暴力的更新到所需要的状态。
假设我们去根号m个定点 , 那么每次查询复杂度就降低到了根号n
所以如果状态能够线性处理出来的话,这个问题就很好解决了。
考虑离线处理。
按照以n为第一关键字 m为第二关键字 排序
思考,如何对于每个 n-1行的前缀和 在能接受的时间代价内求得第n行的前缀和。
通过组合数递推 联想到杨辉三角形,
然后很轻松的想到:
定义 T(i,j) 为 sigma(C(i,0)-C(i,j))
那么 T(i,j)=2*T(i-1,j)-C(i-1,j) 自己在草稿纸上算一算就很容易能求出来了
这样 状态的转移也可以线性的完成了。
总复杂度就控制在了O(n^(3/2)) n为1e5 时限给了两秒 可以接受。
不过有一些细节需要考虑一下。 这里就不讲了,简直耻辱。。。。
用莫队写就简单很多。一样是对m分块 下面放出比赛时写的分块代码 和莫队代码(同学写的 不想在写这题了)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long LL;
using namespace std;
const int MAX=1e5+10;
LL inv[MAX];
LL fac[MAX];
const int MOD=1e9+7;
LL quickpow(LL a,LL b){
LL ans=1;
while(b){
if(b&1){
ans=(ans*a)%MOD;
}
a=(a*a)%MOD;
b>>=1;
}
return ans;
}
void init(){
fac[0] = 1;
for(LL i=1;i1] % MOD;
}
inv[MAX - 1] = quickpow(fac[MAX - 1],MOD - 2);
for(int i = MAX - 2;i >= 0;i--)
inv[i] = inv[i + 1] * (i + 1) % MOD;
}
class Node{
public:
int id,n,m;
bool operator < (const Node &b) const{
if(n==b.n){
return mreturn nlong long n,long long m){
if(n<0 || m< 0 ) return 0;
if(nreturn 0;
return (fac[n]%MOD*inv[n-m]%MOD*inv[m]%MOD)%MOD;
}
Node node[MAX];
LL pre[MAX];
int nowceng=1;
int tot=1;
void up(){
for(int i=1;i<=tot;i++){
pre[i]=pre[i]*2ll-C(nowceng,300*(i));
pre[i]=(pre[i]+MOD)%MOD;
//cout<
}
}
LL ans[MAX];
int main(){
int T;
init();
// int a,b;
// while(cin>>a>>b){
// cout<
// }
// freopen("b.in","r",stdin);
// freopen("b.out","w",stdout);
scanf("%d",&T);
for(int i=0;iscanf ("%d %d",&node[i].n,&node[i].m);
node[i].id=i;
}
sort(node,node+T);
pre[0]=1;
nowceng=1;
tot=0;
for(int i=0;iwhile
(nowcengwhile(node[i].m>tot*300 && (tot+1)*300 <= nowceng){
pre[tot+1]=pre[tot];
tot++;
for(int i=1;i<=300;i++){
pre[tot]+=C(nowceng,(tot-1)*300+i);
pre[tot]%=MOD;
}
}
int base = node[i].m/300;
LL cnt = pre[base];
int top = node[i].m%300;
for(int i=0;i//cout<
cnt=(cnt+C(nowceng,base*300+1+i))%MOD;
//cout<
// cout<
}
ans[node[i].id] = cnt ;
}
for(int i=0;iprintf ("%lld\n",ans[i]);
//cout<
}
}
#include
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=b;i>=a;i--)
#define FIN freopen("in.txt","r",stdin)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
using namespace std;
const int MX=1e5+7;
const int mod=1e9+7;
struct Query{
int n,m,id;
}que[MX];
int pos[MX];
ll inv[MX],f[MX],ans[MX];
bool cmp(Query A,Query B){
if(pos[A.n]!=pos[B.n]) return A.nreturn A.mm;
}
ll qpow(ll a,ll b){ll res=1;while(b){if(b&1) res=(res*a)%mod;a=(a*a)%mod;b>>=1;}return res;}
void init(){
f[1]=1;
for(int i=2;i1]*i)%mod;
for(int i=1;i2);
}
ll C(int n,int m){
if(n < 0 || m < 0 || m > n) return 0;
if(m == 0 || m == n) return 1;
return f[n]*inv[n-m]%mod*inv[m]%mod;
}
ll res=1;
int main(){
init();
int T;scanf("%d",&T);
int block=(int)sqrt(MX);
rep(i,1,MX-1) pos[i]=(i-1)/block;
rep(i,1,T){
scanf("%d%d",&que[i].n,&que[i].m);
que[i].id=i;
}
sort(que+1,que+T+1,cmp);
int N=1,M=0;
rep(i,1,T){
while(N2*res-C(N++,M)+mod)%mod;
}
while(N>que[i].n){
res=((res+C(--N,M))*inv[2])%mod;
}
while(Mm){
res=(res+C(N,++M))%mod;
}
while(M>que[i].m){
res=(res-C(N,M--)+mod)%mod;
}
ans[que[i].id]=res;
}
rep(i,1,T)
printf("%lld\n", ans[i]);
return 0;
}