BZOJ4403 序列统计

access_time    bookmark 题解    comment 0 条评论   

题意

求长度在 $1\sim N$ 之间,由 $[L,R]$ 之间的数构成的单调不降序列的个数。

$N,L,R\le 10^{9}$ 。多组数据,组数 $t\le 100$ 。

题解

令 $M=R-L+1$ ,即可以使用的数的个数。

先考虑固定长度为 $n$ 的情况。

因为是单调不降,所以数字可以重复使用,而只要选出一部分数就能构成一个且仅有一个满足要求的序列。答案就等价于从 $M+n$ 个数中选出 $n$ 个的方案数,即

$$C_{M+n-1}^n$$

那么所有长度的情况即为

$$\begin{aligned} & \sum\limits_{i = 1} ^ N C(i + M - 1, i) \\ = & \sum\limits_{i = 1} ^ N C(i + M - 1, M - 1) \\ = & \sum\limits_{i = 1} ^ N C(i + M - 1, M - 1) + C(m, m) - 1 \\ = & \sum\limits_{i = 2} ^ N C(i + M - 1, M - 1) + C(m, m - 1) + C(m, m) - 1 \\ = & \sum\limits_{i = 2} ^ N C(i + M - 1, M - 1) + C(m + 1, m) - 1 \\ = & \sum\limits_{i = 3} ^ N C(i + M - 1, M - 1) + C(m + 2, m) - 1 \\ = & C(m + n, m) - 1 \\ \end{aligned} $$

然后直接用 $\text{Lucas}$ 定理求解即可。

需要注意的是因为有 $-1$ ,所以可能出现负数。

#include<bits/stdc++.h>
#define ll long long
#define ha 1000003

using namespace std;

inline ll read()
{
    char ch=getchar();
    ll f=1,x=0;
    while (ch<'0' || ch>'9')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return f*x;
}

ll t,n,l,r,fac[ha+2];

inline void get_fac()
{
    fac[0]=fac[1]=1;
    for (ll i=2;i<=ha;i++) fac[i]=fac[i-1]*i%ha;
}

inline ll qpow(ll x,ll y)
{
    ll ans=1;
    while (y)
    {
        if (y&1) ans=ans*x%ha;
        y>>=1;
        x=x*x%ha;
    }
    return ans;
}

inline ll inv(ll x) { return qpow(x,ha-2); }

inline ll C(ll n,ll m)
{
    if (m>n) return 0;
    return fac[n]*(inv(fac[m])*inv(fac[n-m])%ha)%ha;
}

inline ll lucas(ll n,ll m)
{
    if (!m) return 1;
    return lucas(n/ha,m/ha)*C(n%ha,m%ha)%ha;
}

signed main()
{
    get_fac();
    t=read();
    while (t--)
    {
        n=read(); l=read(); r=read();
        ll len=r-l+1;
        printf("%lld\n",(lucas(len+n,len)-1+ha)%ha);
    }
    return 0;
}

新评论

account_circle
称呼不能为空
email
邮箱格式不合法
link
网站格式不合法
textsms
内容不能为空

第一次提交的评论将在审核后显示。