[BZOJ 4403]序列统计
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
1 4 5
2 4 5
Sample Output
2
5
//【样例说明】满足条件的2个序列为[4]和[5]。
5
//【样例说明】满足条件的2个序列为[4]和[5]。
因为可以相等,所以计数会不好处理
还记得上一篇的计数技巧吗?上一篇为了方便分析答案,将所有数-i
同样,这道题要求最长不下降,那么+i,转为最长上升子序列
范围就变成[L+1,R+i],i为序列长度
显然方案数是C(i,i+R-L)=C(R-L,i+R-L)
ans=∑C(k,i+k) k=R-L
但是n很大,O(n)都不能处理
但有C(k,n)+C(k+1,n)=C(k+1,n+1)
ans=C(k,1+k)+C(k,2+k).......C(k,n+k)
=C(1+k,1+k)-1+C(k,1+k)+C(k,2+k)......C(k,n+k)
=C(1+k,2+k)-1+C(k,2+k)......C(k,n+k)
=C(1+k,3+k)-1.........
=C(1+k,n+k+1)-1
由于n,k很大,所以用Lucas定理:C(m,n)=C(m%p,n%p)*C(m/p,n/p)
为了加速lucas,所以用了阶乘逆元(代码中的A),即A[i]=1/(i!)
B代表阶乘
C(x,y)=B[y]*A[x]*A[y-x]%Mod
逆元用线性模逆元公式
复杂度O(Mod+logn)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int Mod=1000003; 7 long long B[1000005],A[1000005]; 8 long long ans; 9 int n,l,r; 10 long long Lucas(int x,int y) 11 { 12 if (x==0) return 1; 13 int xx=x%Mod,yy=y%Mod; 14 if (xx>yy) return 0; 15 long long S=((B[yy]*A[xx])%Mod)*A[yy-xx]%Mod; 16 return (S*Lucas(x/Mod,y/Mod))%Mod; 17 } 18 int main() 19 {int T,i; 20 cin>>T; 21 A[1]=1;A[0]=1;B[0]=1; 22 for (i=2;i<=1000003;i++) 23 A[i]=((Mod-Mod/i)*A[Mod%i])%Mod; 24 for (i=1;i<=1000003;i++) 25 { 26 A[i]=(A[i]*A[i-1])%Mod; 27 B[i]=(B[i-1]*i)%Mod; 28 } 29 while (T--) 30 { 31 cin>>n>>l>>r; 32 ans=Lucas(r-l+1,r-l+n+1); 33 cout<<(ans-1+Mod)%Mod<<endl; 34 } 35 }