bzoj4403:序列统计

我好傻啊

题目

先来看看长度只能为\(n\)的情况

那么答案非常显然是\(\binom{m+n-1}{n}\)

其中\(m=R-L+1\)

因为我们要构造一个非降序列,显然可能一个数会被选择多次,组合非常不好做,于是我们可以把每一个数的下标加上其对应的下标那么现在的值域范围就变成了\([L+1,R+n]\),从这个区间里选数的话,我们把选出来的数减去选好之后对应的下标,发现得到的数就来自于原来的\([L,R]\),于是就变成了从\(R+n-L-1+1=n+m-1\)里选择的\(n\)个数,就是\(\binom{n+m-1}{n}\)

也可以这样理解,视为把\(n\)个小球放到\(m\)个盒子里,这样的话多个小球可以放到同一个盒子里,就对应着一个数可以被选择多次,盒子也可以是空着的,对应着一个数可以不被选择,根据插板法,这样的方案数就是\(\binom{n+m-1}{m-1}=\binom{n+m-1}{n}\)

现在的问题变成了求

\[\sum_{i=1}^{n}\binom{i+m-1}{m-1}\]

之后画一下柿子就是\(\binom{n+m}{m}=\binom{n+m}{n}\)

之后上\(Lucas\)就好了

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define re register
#define maxn 1000005
const LL mod=1000003;
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
LL fac[maxn],inv[maxn];
inline LL C(LL n,LL m)
{
    if(!m) return 1;
    if(!n) return 0;
    if(n==m) return 1;
    if(m>n) return 0;
    return fac[n]*inv[fac[m]*fac[n-m]%mod]%mod;
}
LL Lucas(LL n,LL m)
{
    if(!m) return 1;
    if(!n) return 0;
    if(n<mod&&m<mod) return C(n,m);
    return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
}
int n,m,T,L,R;
int main()
{
    T=read();
    fac[0]=1;
    for(re int i=1;i<=mod;i++) fac[i]=fac[i-1]*i%mod;
    inv[1]=1;
    for(re int i=2;i<=mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    while(T--)
    {
        n=read(),L=read(),R=read();
        m=R-L+1;
        printf("%lld\n",(Lucas(n+m,m)-1+mod)%mod);
    }
    return 0;
}

转载于:https://www.cnblogs.com/asuldb/p/10205701.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值