HDU 6333 Problem B. Harvest of Apples(莫队算法)

题目描述:

给出T组n和m(1<=T<=1e5, 1<=m<=n<=1e5)。

\sum_{i=0}^{m}C_{n}^{i}

题目分析:

记:S_{n}^{i}=\sum_{i=0}^{m}C_{n}^{i}

通过杨辉三角得出:

S_{L}^{R}=S_{L}^{R-1}+C_{L}^{R}          ==           S_{L}^{R}=S_{L}^{R+1}-C_{L}^{R+1}

S_{L}^{R}=2*S_{L-1}^{R}-C_{L-1}^{R}      ==      S_{L}^{R}=(S_{L+1}^{R}+C_{L}^{R})/2

所以只需要求出1e5以内的全部组合数就可以进行任意移动了,组合数模板:

const int N = 1e7;		//复杂度O(n)
const ll mod = 1e9 + 7;
int F[N], Finv[N], inv[N];//F是阶乘,Finv是阶乘的逆元
//X 关于 mod 的逆元为 x^(mod - 2);
void init(){
	F[0] = Finv[0] = inv[1] = 1;
	for (register int i = 2; i < N; i++)
		inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;
	for (register int i = 1; i < N; i++){
		F[i] = F[i - 1] * 1ll * i % mod;
		Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;
	}
}
int comb(int n, int m){///comb(n, m)就是C(n, m)
	if (m < 0 || m > n) return 0;
	return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}

AC代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N = 1e5+7;        //复杂度O(n)
const ll mod = 1e9 + 7;
int F[N], Finv[N], inv[N];
void init(){
    F[0] = Finv[0] = inv[1] = 1;
    for (register int i = 2; i < N; i++)
        inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;
    for (register int i = 1; i < N; i++){
        F[i] = F[i - 1] * 1ll * i % mod;
        Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;
    }
}
int comb(int n, int m){///comb(n, m)就是C(n, m)
    if (m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}

inline int read(){//读入整数
    int k = 0, f = 1; char c = getchar();
    while (c<'0' || c>'9')c == '-' && (f = -1), c = getchar();
    while ('0' <= c&&c <= '9')k = k * 10 + c - '0', c = getchar();
    return k*f;
}
struct query{
    int l,r,id,ans;
}q[100005];
int m;
bool cmp1(query a,query b){
    if(a.l/317==b.l/317)
        return a.r<b.r;
    else return a.l/317<b.l/317;
}
bool cmp2(query a,query b){
    return a.id<b.id;
}
void work(){
    int L=1,R=0,tmp;
    ll S=1;
    for(int i=0;i<m;i++){
        while(q[i].r<R){
            tmp=comb(L,R);
            S=(S-tmp+mod)%mod;
            R--;
        }
        while(q[i].r>R){//之前以为注释部分不加进行移动会出错,其实能AC
//            if(L==R){
//                tmp=comb(L,R);
//                S=(2*S-tmp+mod)%mod;
//                L++;
//            }
            R++;
            tmp=comb(L,R);
            S=(S+tmp)%mod;
        }
        while(q[i].l<L){
//            if(L==R){
//                tmp=comb(L,R);
//                S=(S-tmp+mod)%mod;
//                R--;
//            }
            L--;
            tmp=comb(L,R);
            S=((S+tmp)*inv[2])%mod;
        }
        while(q[i].l>L){
            tmp=comb(L,R);
            S=(2*S-tmp+mod)%mod;
            L++;
        }
        q[i].ans=S;
    }
}
int main(){
    init();
    m=read();
    for(int i=0;i<m;i++)
        q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q,q+m,cmp1);
    work();
    sort(q,q+m,cmp2);
    for(int i=0;i<m;i++){
        printf("%d\n",q[i].ans);
    }
    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值