Problem B. Harvest of ApplesTime Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 3221 Accepted Submission(s): 1248 Problem Description There are n apples on a tree, numbered from 1 to n . Input The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases. 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 |
题意:
求从n个苹果种取出最多m个的方法数。
做法:
很神奇的居然是用莫队写的,就参考机房大神写了题解。
求S(n,m)=ΣC(n,i)(0<=i<=m)S(n,m)=ΣC(n,i) (0<=i<=m)。
可推出S(n,m)=S(n,m-1)+C(n,m),S(n,m)=2*S(n-1,m)-C(n-1,m),这样就可以用莫队了,转移是O(1),总复杂度O(T*sqrt(maxn))。
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=200002;
const int mod=(int)1e9+7;
typedef long long ll;
int biao,n;
ll fac[maxn],inv[maxn],anss[maxn];
struct node{
int n,k,id;
node(){}
node(int n,int k,int id):n(n),k(k),id(id){}
};
bool cmp(node a,node b){
return a.n<b.n;
}
ll quick(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
vector<node> ve[1005];
ll C(int n,int m){
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
biao=sqrt(maxn);
fac[0]=1;
for(int i=1;i<=100000;i++)
fac[i]=fac[i-1]*i%mod;
inv[100000]=quick(fac[100000],mod-2);
for(int i=99999;~i;i--){
inv[i]=inv[i+1]*(i+1)%mod;//反向线性求逆元
}
int nn,kk;
int mma=-1;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&nn,&kk);
int aim=kk/biao;
mma=max(mma,aim);
ve[aim].push_back(node(nn,kk,i));
}
for(int i=0;i<=100000/biao;i++){
if(!ve[i].size()) continue;
sort(ve[i].begin(),ve[i].end(),cmp);
ll l=ve[i][0].n,r=-1,res=0;
for(int j=0;j<ve[i].size();j++){
while(l<ve[i][j].n)
res=(2*res+mod-C(l++,r))%mod;
while(r<ve[i][j].k)
res=(res+C(l,++r))%mod;
while(r>ve[i][j].k)
res=(res+mod-C(l,r--))%mod;
anss[ve[i][j].id]=res;
}
}
for(int i=1;i<=n;i++)
printf("%lld\n",anss[i]);
return 0;
}