bzoj 4403: 序列统计

bzoj 4403: 序列统计
                      Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1062  Solved: 497
[Submit][Status][Discuss]

Description

给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对10^6+3取模的结果。

Input

输入第一行包含一个整数T,表示数据组数。
第2到第T+1行每行包含三个整数N、L和R,N、L和R的意义如题所述。
1≤N,L,R≤10^9,1≤T≤100,输入数据保证L≤R。

Output

输出包含T行,每行有一个数字,表示你所求出的答案对10^6+3取模的结果。

Sample Input

2
1 4 5
2 4 5

Sample Output

2
5
//【样例说明】满足条件的2个序列为[4]和[5]。

很简单的组合数学题。
首先发现元素大小并没有什么卵用,只需要知道可选数的种类即可。
单调不降就相当于把排列变成组合(组合的含义就是单调不降排列数量)。
设len=r-l+1,那么答案就是C(len,1)+C(len+1,2)+...+C(len+n-1,n)。(有可重复元素的组合)
化简一下,把上式+C(len,0)再-C(len,0),可得:
ANS=C(len+n,n)-1。

发现mod才是10^6级别的,所以把阶乘和逆元处理出来之后再写个卢卡斯就可以了
(而且这个卢卡斯最多只会跑两层)。
 
#include<bits/stdc++.h>
#define ll long long
#define ha 1000003
#define maxn 1000005
using namespace std;
ll jc[maxn],ni[maxn];
ll T,l,r,n,len;

inline ll ksm(ll x,ll y){
    ll an=1;
    for(;y;y>>=1,x=x*x%ha) if(y&1) an=an*x%ha;
    return an;
}

inline void init(){
    jc[0]=1;
    for(int i=1;i<ha;i++) jc[i]=jc[i-1]*(ll)i%ha;
    ni[ha-1]=ksm(jc[ha-1],ha-2);
    for(int i=ha-2;i>=0;i--) ni[i]=ni[i+1]*(ll)(i+1)%ha;
}

inline ll C(ll x,ll y){
    if(x<y) return 0;
    return jc[x]*ni[y]%ha*ni[x-y]%ha;
}

inline ll Lucas(ll x,ll y){
    ll ans=1,px,py;
    while(x||y){
        px=x%ha,py=y%ha;
        x/=ha,y/=ha;
        ans=ans*C(px,py)%ha;
    }
    return ans;
}

int main(){
    init();
    
    scanf("%lld",&T);
    while(T--){
        scanf("%d%d%d",&n,&l,&r);
        len=r-l+1;
        
        printf("%lld\n",(Lucas(len+n,n)-1+ha)%ha);
    }
    
    return 0;
}

 

posted @ 2018-01-07 19:11  蒟蒻JHY  阅读(228)  评论(0编辑  收藏  举报