题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6333
题意:求C(n,0)+C(n,1)+...+C(n,m)的和
思路:题解说可以莫队做,知道S(n,m)即可向附近项转化,想想也是,然后就写了下。(S(n,m)为前m项和)
先列出递推式:S(n+1,m)=2*(n,m)-C(n,m) ; S(n-1,m)=S(n,m)+C(n-1,m);
S(n,m+1)=S(n,m)+C(n,m+1) ; S(n,m-1)=S(n,m)-C(n,m)
这里还必须先预处理出组合数,否则不能O(1)转移。组合数取模又牵扯到逆元,就O(n)预处理出逆元,然后就直接莫队就行啦。
具体看代码
代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define fuck(x) cout<<"<"<<x<<">"<<endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int pos[maxn];
LL ans[maxn];
LL sum;
struct query{
int n,k,id;
}q[200005];
bool cmp(query a,query b){
if (pos[a.n]==pos[b.n]) return a.k<b.k;
return pos[a.n]<pos[b.n];
}
LL inv[maxn], fac[maxn];
LL pow_mod(LL a, LL b, int p){
LL ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
void get(int n, int p) {
fac[0] = 1;
for (int i = 1; i <= n; ++i) {
fac[i] = i * fac[i - 1] % p;
}
inv[n] = pow_mod(fac[n], p-2 , p);
for (int i = n-1; i >= 0; --i) {
inv[i] = inv[i + 1] * (i + 1) % p;
}
}
LL c(int a,int b){
return 1LL*fac[a] * inv[b] % mod * inv[a - b] % mod;
}
int main (){
int n=100000,m;
get(n,mod);
scanf ("%d",&m);
for (int i=1;i<=m;i++){
scanf ("%d%d",&q[i].n,&q[i].k);
q[i].id=i;
}
int block = (int)sqrt(n);
for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
sort(q+1,q+1+m,cmp);
int l=1,r=0;
sum=1;
for (int i=1;i<=m;i++){
while (r<q[i].n) sum=(2*sum-c(r,l)+mod)%mod,r++;
while (r>q[i].n) sum=((sum+c(r-1,l))%mod*inv[2]%mod)%mod,r--;
while (l<q[i].k) sum=(sum+c(r,l+1))%mod,l++;
while (l>q[i].k) sum=(sum-c(r,l)+mod)%mod,l--;
ans[q[i].id]=sum;
}
for (int i=1;i<=m;i++){
printf("%lld\n", ans[i]);
}
}