bzoj 4403: 序列統計【lucas+組合數學】
阿新 • • 發佈:2018-11-11
首先,給一個單調不降序列的第i位+i,這樣就變成了單調上升序列,設原來資料範圍是(l,r),改過之後變成了(l+1,r+n)
在m個數裡選長為n的一個單調上升序列的方案數為\( C_m^n \),也就是隨便選n個數只能組成惟一的單調上升序列,所以要求的式子就變成了
\[ \sum_{i=1}^{n}C_{r-l+i}^{i} \]
這樣看著比較難受,我們把它改成
\[ \sum_{i=1}^{n}C_{r-l+i}^{r-l} \]
我們在開頭加一個\( C_{r-l+1}^{r-l+1} \),這樣根據\( C_n^m=C_{n-1}^m+C_{n-1}^{m-1} \),他就可以和式子的第一項\( C_{r-l+1}^{r-l} \)合併為\( C_{r-l+2}^{r-l+1} \),然後這個又可以可第二個合併,以此類推,最後這個式子就會合併為\( C_{r-l+n+1}^{r-l+1} \),然後再減掉\( C_{r-l+1}^{r-l+1}=1 \)即可
然後用lucas求這個組合數即可
#include<iostream> #include<cstdio> using namespace std; const long long N=1000010,mod=1e6+3; long long T,n,l,r,fac[N],inv[N]; long long ksm(long long a,long long b) { long long r=1; while(b) { if(b&1) r=r*a%mod; a=a*a%mod; b>>=1; } return r; } long long C(long long n,long long m) { if(m>n) return 0; return fac[n]*inv[m]%mod*inv[n-m]%mod; } long long lucas(long long n,long long m) { if(m>n) return 0; return n<mod?C(n,m):lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod; } int main() { scanf("%lld",&T); fac[0]=1,inv[0]=1; for(int i=1;i<mod;i++) fac[i]=fac[i-1]*i%mod; inv[mod-1]=ksm(fac[mod-1],mod-2); for(int i=mod-2;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mod; while(T--) { scanf("%lld%lld%lld",&n,&l,&r); printf("%lld\n",(lucas(r-l+n+1,r-l+1)-1+mod)%mod); } return 0; }