[莫队]HDU6333(2018多校练习赛第四场 Problem B)【Harvest of Apples】题解

题目大意

f(n,m)=mi=0Cin f ( n , m ) = ∑ i = 0 m C n i , 多组数据。

解题分析

上莫队。

如果已经求出了 f(n,m) f ( n , m ) ,那么如何求出 f(n+1,m) f ( n + 1 , m ) f(n,m+1) f ( n , m + 1 ) 呢?

f(n,m+1)=f(n,m)+Cm+1n f ( n , m + 1 ) = f ( n , m ) + C n m + 1

f(n+1,m)=mi=0Cin+1=mi=1(Cin+Ci1n)+1=f(n,m)+f(n,m1)=2f(n,m)Cnm f ( n + 1 , m ) = ∑ i = 0 m C n + 1 i = ∑ i = 1 m ( C n i + C n i − 1 ) + 1 = f ( n , m ) + f ( n , m − 1 ) = 2 ∗ f ( n , m ) − C m n

所以可以 O(1) O ( 1 ) 转移,这样就可以用莫队了。

示例程序

(题目传送门)

#include<cmath>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int tt=1000000007,invt=(tt+1)>>1,maxn=100005;
int S,q,h[maxn],ans[maxn];
LL num,fac[maxn],inv[maxn];
struct data{
    int L,R,id;
    data (int L=0,int R=0,int id=0):L(L),R(R),id(id){}
    bool operator < (const data b)const{
        if (h[L]==h[b.L]) return R<b.R;
        return L<b.L;
    }
}a[100005];
inline void readi(int &x){
    x=0; char ch=getchar();
    while ('0'>ch||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
LL ksm(LL x,int y){
    LL sum=1,w=x;
    for (;y;y>>=1,w=(w*w)%tt) if (y&1) sum=(sum*w)%tt;
    return sum%tt;
}
void blocker(int n){
    S=sqrt(n);
    for (int i=1;i<=n;i++) h[i]=(i-1)/S+1;
}
LL C(int n,int m){
    if (n==m) return 1;
    return (fac[n]*inv[m]%tt)*inv[n-m]%tt;
}
int main()
{
    freopen("apple.in","r",stdin);
    freopen("apple.out","w",stdout);
    readi(q); blocker(q);
    for (int i=1,x,y;i<=q;i++) {readi(x); readi(y); a[i]=data(y,x,i);}
    num=1; sort(a+1,a+q+1);
    fac[0]=1; for (int i=1;i<=1e5;i++) fac[i]=(fac[i-1]*i)%tt;
    for (int i=0;i<=1e5;i++) inv[i]=ksm(fac[i],tt-2);
    for (int i=1,L=0,R=0;i<=q;i++){
        while (R<a[i].R) num=((num<<1)-C(R++,L)+tt)%tt;
        while (R>a[i].R) num=(num+C(--R,L))%tt*invt%tt;
        while (L<a[i].L) num=(num+C(R,++L))%tt;
        while (L>a[i].L) num=(num-C(R,L--)+tt)%tt;
        ans[a[i].id]=num;
    }
    for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值