hdu6333 多校第四场Problem B. Harvest of Apples(莫队)

题目链接: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]);
    }
}






 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值