您的位置:首页 > 其它

4403: 序列统计 组合数学+Lucas定理

2016-02-17 09:28 288 查看
组合的知识大大欠缺啊。。好好学习一下。

先膜出题人yts1999大爷。

首先转化一下问题:

求长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。我们进行加标号的操作,将每一位的值都+i,即转化为:求长度在1到N之间,元素大小都在L+1到R+N之间的单调递增序列的数量(不懂画个图)。

那么这个问题就相当于在区间[L+1,R+N]这R−L+N个数中选择N个的方案数,即CNR−L+N即CR−LR−L+N。

为了表述方便,我们令M=R−L+1,上式转化为CM−1M+N−1。

所以答案为∑i=1NCM−1i+M−1

因为CMN=CMN−1+CM−1N−1

所以我们有以下等价转化:

∑Ni=1CM−1i+M−1

=(∑Ni=1CM−1i+M−1)+CMM−1

=(∑Ni=2CM−1i+M−1)+CMM+1−1

=(∑Ni=3CM−1i+M−1)+CMM+2−1

...

=CMN+M−1

然后用Lucas定理解决。

#include<iostream>
#include<cstdio>
#define ll long long
#define M 1000003
using namespace std;
ll fac[M],inv[M];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void pre()
{
fac[0]=inv[1]=inv[0]=1;
for (int i=1;i<M;i++)
fac[i]=fac[i-1]*i%M;
for (int i=2;i<M;i++)
inv[i]=(M-M/i)*inv[M%i]%M;
for (int i=1;i<M;i++)
inv[i]=inv[i]*inv[i-1]%M;
}
ll C(int n,int m)
{
if (n<m) return 0;
if (n<M&&m<M)
return fac
*inv[m]%M*inv[n-m]%M;
return C(n/M,m/M)*C(n%M,m%M)%M;
}
int main()
{
int T=read();
pre();
while (T--)
{
int n=read(),l=read(),r=read(),m=r-l+1;
printf("%d\n",(C(n+m,m)+M-1)%M);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: