首页 > 技术文章 > bzoj 4403: 序列统计

Yuzao 2018-02-02 22:50 原文

Description

给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对10^6+3取模的结果。

Solution

将所有元素\(a[i]\)加上\(i\)之后,就变成求单调上升序列了,那么\(a[i]\)的取值范围就是\([L+1,R+n]\),且只有 \(R-L+n\) 种选择了
如果要求的序列长度为 \(n\),那么答案就是 \(C_{R-L+n}^{n}\)
本题要求的是 \(\sum_{i=1}^{n}C_{R-L+i}^{R-L}\)
\(R-L=j\)
要求的就是 \(C_{j+1}^{j}+C_{j+2}^{j}....+C_{j+n}^{j}\)
加入一项 \(C_{j+1}^{j+1}\)
原式变为 \(C_{j+1}^{j+1}-1+C_{j+1}^{j}+C_{j+2}^{j}....+C_{j+n}^{j}\)
由组合数递推式:\(C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m}\) 逐项合并
就可以得到最后的答案:\(C_{n+R-L+1}^{R-L+1}\)
观察到模数较小且为质数,直接Lucas求即可.

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=1e6+3;
int Fac[N];
int qm(int x,int k){
  int sum=1;
  while(k){
    if(k&1)sum=1ll*sum*x%mod;
    x=1ll*x*x%mod;k>>=1;
  }
  return sum;
}
inline int C(int n,int m){
  if(n<m)return 0;
  return 1ll*Fac[n]*qm(Fac[m],mod-2)%mod*qm(Fac[n-m],mod-2)%mod;
}
inline int Lucas(int n,int m){
  if(m==0)return 1;
  return 1ll*Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  int n,L,R,T;cin>>T;
  Fac[0]=1;for(int i=1;i<N;i++)Fac[i]=1ll*Fac[i-1]*i%mod;
  while(T--){
    scanf("%d%d%d",&n,&L,&R);
    printf("%d\n",(Lucas(n+R-L+1,R-L+1)-1+mod)%mod);
  }
  return 0;
}

推荐阅读