BZOJ P4403 序列统计【组合数学】【Lucas】

题目分析:

显然对于题目中所表示的范围:L~R只表示元素所能够取得的区间大小/长度,所以我们可以忽略区间元素本身的大小,只考虑元素可以去到多少个值。于是,我们就可以将题目中的:L~R 区间YY成一个压缩后的区间:1~(R-L+1),注意:这个区间的压缩是不影响最后结果的(当N固定,L=3,R=6与L=1,R=4意义是一样的)。这个时候就可以显然看出这个序列的每个元素的都有(R-L+1)种取值。这个时候我们来转换一下问题,先令M=R-L+1,即每个元素都有M种取值范围,那么原问题就相当于转换成了“N个球放入M个盒子里,盒子可以为空,球也可以不选”的问题了,对于这个问题那么就显然组合数为C(M+N,M),但是不能存在N个球一个都不选的选法,但是这种选法又包含在了转换问题里面,所以最后的答案要-1。即最后的答案为:C(M+N,M)-1。

补充:为什么上面两个问题可以互相转换。对于“N个球放入M个盒子里,盒子可以为空,球也可以不选”的问题,因为盒子可以为空,求也可以不选,所以我们不妨把它假想为有两个盒子,一个盒子有N个球,一个盒子有M个球,两个盒子最后一共取出M个球,所以这个问题的答案就是C(M +N ,M)了。那么再来考虑原问题:“N个元素每个元素有M中取值,允许存在元素不取值,允许不是每个取值都要取到”的问题,就与前面的盒子问题相对应了,不过此处不能存在N个元素都不取值的情况,所以最后答案在C(N+M,M)的基础上-1即可。不知道大家会不会存在这样一个疑惑,就是题目中提到的单调不降如何处理?这样想:有1个球放在1号盒子与2号盒子里都是一样的,只属于一种方案,那么两个数4,5组合在一起有两种可能45和54,但是要因为单调不降,所以最后的方案也只有一个45。

参考代码(此处为旧代码,尚未更新,好像加强了数据):

#include <cstdio>  
#define LL long long  
const LL Mod=1e6+3;  
const LL Inf=1e18;  
inline LL Read(){  
    LL X=0;char CH=getchar();bool F=0;  
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}  
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}  
    return F?-X:X;  
}  
inline void Write(LL X){  
    if(X<0)X=-X,putchar('-');  
    if(X>9)Write(X/10);  
    putchar(X%10+48);  
}  
LL KSC(LL A,LL B,LL P){  
    A%=P,B%=P;  
    LL C=(long double)A*B/P;  
    LL Ans=A*B-C*P;  
    if(Ans<0){  
        Ans+=P;  
    } else if(Ans>=P) {  
        Ans-=P;  
    }return Ans;  
}  
LL KSM(LL A,LL B,LL C){  
    int Ans=1%C;  
    for(;B;B>>=1){  
        if(B&1){  
            Ans=KSC(Ans,A,C);  
        }A=KSC(A,A,C);  
    }return Ans;  
}  
LL C(LL A,LL B)  
{  
    if(A<B) return 0;  
    if(A==B) return 1;  
    B=B>A-B?A-B:B;  
    LL GA=1ll,GB=1ll;  
    for(LL I=0;I<B;I++)  
    {  
        GA=(GA*(A-I))%Mod;  
        GB=(GB*(B-I))%Mod;  
    }  
    return (GA*KSM(GB,Mod-2,Mod))%Mod;  
}  
LL Lucas(LL N,LL M)  
{  
    if(M==0) return 1;  
    return C(N%Mod,M%Mod)*Lucas(N/Mod,M/Mod)%Mod;  
}
int main()  
{  
    LL T=Read(),N,L,R;  
    while(T--)  
    {  
        N=Read();  
        L=Read();  
        R=Read();  
        LL M=R-L+1;  
        Write(((Lucas(M+N,M)-1)%Mod+Mod)%Mod);
        putchar('\n');  
    }  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/80486093