题目链接:序列统计
首先,L与R实际上是没太大意义的,因为我们需要的只是L和R之间含有多少个数,即R-L+1个数。其次,要注意一点,在一个序列中,数字是可以重复的。以样例中的2 4 5为例,符合要求的序列有{4},{5},{4,5},{4,4},{5,5}。事实上,问题可以转化为“有R-L+1个不同的盒子,若要将i(1<=i<=n)个相同的小球放进这些盒子里(某些盒子可以为空),问对于所有的i,放法的总和是多少?”其中,不同的盒子代表着不同的数,在一个盒子中放入一个球,相当于选取一次该数字作为序列中的成员。再将问题抽象一下,即为“将i个小球划分成k堆(1<=k<=i),问对于所有的i,划分方法的总和是多少?”对于这个问题,我们可以直接用C(m+n,n)求解(对于本题是C(seg+n,n),seg=R-L+1)另外,通过观察可知(其实是我不会推导。。。。。。),通过C(m+n,n)求出的数会比正确答案大1,故最终答案为C(seg+n,n)-1。 又因为10^6+3为素数,故可以用Lucas。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long ll;
ll fpow(ll a,ll b,ll p)
{
ll ans=1;a%=p;
while(b)
{
if(b&1)
ans=(ans*a)%p;
a=(a*a)%p;
b>>=1;
}
return ans;
}
ll inv(ll x,ll p)
{
return fpow(x,p-2,p);
}
ll comb(ll n,ll m,ll p)
{
if(n<m) return 0;
ll up=1;ll down=1;
for(int i=n-m+1;i<=n;i++) up=(up*i)%p;
for(int i=1;i<=m;i++) down=(down*i)%p;
return up*inv(down,p)%p;
}
ll lucas(ll a,ll b,ll p)
{
return !b?1:lucas(a/p,b/p,p)*comb(a%p,b%p,p)%p;
}
int main()
{
int t;
ll n,lef,rig;
ll p=3+1e6;
scanf("%d",&t);
while(t--)
{
scanf("%lld %lld %lld",&n,&lef,&rig);
ll seg=rig-lef+1;
ll ans=0;
ans=(lucas(seg+n,n,p)+p-1)%p;
printf("%lld\n",ans);
}
return 0;
}