noi.ac 405 bzoj 4403 序列统计 题解

博客观赏效果更佳

题意简述

noi.ac再次蒯题,实锤了…

请你求长度在 [ 1 , n ] [1,n] [1,n] 范围内,值域在 [ l , r ] [l,r] [l,r] 范围内的序列中,不下降序列有多少个。答案对 1000003 1000003 1000003(是质数)取膜。

多组数据,数组组数 T ≤ 100 T\le 100 T100 ,每组数据 n , l , r ≤ 1 e 9 n,l,r\le 1e9 n,l,r1e9 ,并且保证 l ≤ r l\le r lr

思路框架

首先,在 [ l , r ] [l,r] [l,r] 范围内,和在 [ 1 , r − l + 1 ] [1,r-l+1] [1,rl+1] 范围内,没有本质上的区别。
m = r − l + 1 m=r-l+1 m=rl+1,然后答案就是 C n + m m − 1 C_{n+m}^{m}-1 Cn+mm1

具体思路

我们先求长度固定为 k k k 的时候,有多少满足条件的序列,然后取遍 k = 1 , 2 ⋯ n k=1,2\cdots n k=1,2n ,求和。

求有多少固定长度非严格上升子序列
严格上升怎么做

长度为 k k k 的时候,值域在 [ 1 , m ] [1,m] [1,m] 内的严格上升序列的格式就是 C m k C_{m}^{k} Cmk 。因为我们只要在 [ 1 , m ] [1,m] [1,m] 内选出来 k k k 个数,然后把它排一下序,那就能得到一个长度为 k k k ,值域在 [ 1 , m ] [1,m] [1,m] 内的一个严格上升序列了。

如何转化成非严格上升

我们在选严格上升序列的时候,假设我们当前选到的数为 x x x,那么下一个位置珂以是 x + 1 , x + 2... m x+1,x+2...m x+1,x+2...m,有 m − x m-x mx 种选择。而选非严格上升序列的时候,却有 $m-x+1 $种选择。

那这个时候,我们只要把 m m m 变成 m + 1 m+1 m+1 ,那答案就和严格上升的时候一样了!!

序列的长度为 k k k ,那么我们在选第 [ 1 , k − 1 ] [1,k-1] [1,k1]这些位置的时候,都要把 m m m 变成 m + 1 m+1 m+1。那一共就是变成 m + k − 1 m+k-1 m+k1

总结一下,长度为 k k k 值域在 [ 1 , m ] [1,m] [1,m] 之间的非严格上升序列个数为 C m + k − 1 k C_{m+k-1}^{k} Cm+k1k

优化求和

我们要求 ∑ i = 1 n C m + i − 1 i = C m 1 + C m + 1 2 + C m + 2 3 . . . + C m + n − 1 n \sum\limits_{i=1}^{n} C_{m+i-1}^{i}=C_{m}^1+C_{m+1}^2+C_{m+2}^3...+C_{m+n-1}^{n} i=1nCm+i1i=Cm1+Cm+12+Cm+23...+Cm+n1n

显然, C n m = C n − 1 m + C n − 1 m − 1 C_{n}^{m}=C_{n-1}^{m}+C_{n-1}^{m-1} Cnm=Cn1m+Cn1m1

那也就是说,我们珂以用两个相邻的 C n x x x C_{n}^{xxx} Cnxxx 得到一个 C n + 1 x x x C_{n+1}^{xxx} Cn+1xxx

那么我们考虑给第一项加上一个 C m 0 C_{m}^{0} Cm0,也就是 1 1 1,然后最后减掉一个 C m 0 C_{m}^{0} Cm0

那我们开始推式子了,系好安全带(为了方便理解,我拆开 Σ \Sigma Σ):
原式
= C m 0 + C m 1 + C m + 1 2 + C m + 2 3 . . . + C m + n − 1 n − 1 =C_{m}^{0}+C_{m}^{1}+C_{m+1}^{2}+C_{m+2}^3...+C_{m+n-1}^n-1 =Cm0+Cm1+Cm+12+Cm+23...+Cm+n1n1
= C m + 1 1 + C m + 1 2 + C m + 2 3 + . . . + C m + n − 1 n − 1 =C_{m+1}^{1}+C_{m+1}^{2}+C_{m+2}^3+...+C_{m+n-1}^n-1 =Cm+11+Cm+12+Cm+23+...+Cm+n1n1
= C m + 2 2 + C m + 2 3 + . . . . + C m + n − 1 n − 1 =C_{m+2}^{2}+C_{m+2}^{3}+....+C_{m+n-1}^n-1 =Cm+22+Cm+23+....+Cm+n1n1
= C m + n − 1 n − 1 + C m + n − 1 n − 1 =C_{m+n-1}^{n-1}+C_{m+n-1}^{n}-1 =Cm+n1n1+Cm+n1n1
= C m + n n − 1 =C_{m+n}^{n}-1 =Cm+nn1

所以答案就是 C m + n n − 1 C_{m+n}^{n}-1 Cm+nn1。预处理阶乘(逆元)+Lucas定理。

代码

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
    #define mod 1000003
    #define N (mod<<1)
    #define int long long 
    #define F(i,l,r) for(int i=l;i<=r;++i)
    #define D(i,r,l) for(int i=r;i>=l;--i)
    #define Fs(i,l,r,c) for(int i=l;i<=r;c)
    #define Ds(i,r,l,c) for(int i=r;i>=l;c)
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define FK(x) MEM(x,0)
    #define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
    #define p_b push_back
    #define sz(a) ((int)a.size())
    #define iter(a,p) (a.begin()+p)
    void R1(int &x)
    {
        x=0;char c=getchar();int f=1;
        while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=(f==1)?x:-x;
    }
    void Rd(int cnt,...)
    {
        va_list args;
        va_start(args,cnt);
        F(i,1,cnt) 
        {
            int* x=va_arg(args,int*);R1(*x);
        }
        va_end(args);
    }

    int fac[N],ifac[N];
    //阶乘,和阶乘的逆元
    void Init()
    {
        fac[0]=1;
        F(i,1,mod-1) fac[i]=fac[i-1]*i%mod;
        ifac[mod-1]=mod-1;
       //mod是质数,那么(mod-1)! %mod=mod-1,这个是Wilson定理
       //然后mod-1的逆元,显然是mod-1
        D(i,mod-2,0) ifac[i]=ifac[i+1]*(i+1)%mod;
    }
    int n,l,r;
    void Input()
    {
        Rd(3,&n,&l,&r);
    }

    int C(int n,int m) //Lucas定理
    {
        if (m>n) return 0;
        if (n<mod and m<mod)
        {
            return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
        }
        return C(n/mod,m/mod)*C(n%mod,m%mod)%mod;
    }
    void Soviet()
    {
        int len=r-l+1; //len就是m了
        printf("%lld\n",(C(n+len,len)+mod-1)%mod);
    }

    #define Flan void
    Flan IsMyWife()
    {
        Init();
        int t;R1(t);
        F(i,1,t)
        {
            Input();
            Soviet();
        }
    }
    #undef int //long long 
}
int main()
{
    Flandre_Scarlet::IsMyWife();
    getchar();getchar();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值