[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

Sample Output

2
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 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7636805.html