BZOJ1856【SCOI2010】字符串题解(组合数学+Catalan数)

题目:BZOJ1856.
题目大意:给定 n n n 1 1 1 m m m − 1 -1 1,求组成的序列每一个前缀和都不小于 0 0 0的方案数.
1 ≤ n , m ≤ 1 0 6 1\leq n,m\leq 10^6 1n,m106.

首先这个问题很像经典的Catalan数问题,但这里 1 1 1 − 1 -1 1的个数是不等的.

上面的Catalan数链接的问题4拓展已经把这个问题讲的很清楚了这里不讲了,直接上结论答案为:
{ 0 n < m C n + m m − C n + m m − 1 n ≥ m \left\{\begin{matrix} 0&n<m\\ C_{n+m}^{m}-C_{n+m}^{m-1}&n\geq m \end{matrix}\right. {0Cn+mmCn+mm1n<mnm

有了结论后就是一道简单题了.

时间复杂度 O ( n ) O(n) O(n).

代码如下:

#include
  using namespace std;
 
#define Abigail inline void
typedef long long LL;

const int N=1000000,mod=20100403;

int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
int sub(int a,int b){return a-b<0?a-b+mod:a-b;}
int mul(int a,int b){return (LL)a*b%mod;}
int sqr(int a){return a=(LL)a*a%mod;}
void sadd(int &a,int b){a=add(a,b);}
void ssub(int &a,int b){a=sub(a,b);}
void smul(int &a,int b){a=mul(a,b);}
void ssqr(int &a){a=sqr(a);}

int n,m,inv[N*2+9];

void Pre_inv(int n){
  inv[1]=1;
  for (int i=2;i<=n+m;++i) inv[i]=mul(mod-mod/i,inv[mod%i]);
}

int Calc_C(int n,int m){
  int res=1;
  for (int i=1;i<=n;++i) smul(res,i);
  for (int i=1;i<=m;++i) smul(res,inv[i]);
  for (int i=1;i<=n-m;++i) smul(res,inv[i]);
  return res;
}

Abigail into(){
  scanf("%d%d",&n,&m);
}

Abigail work(){
  Pre_inv(n);
}

Abigail outo(){
  printf("%d\n",n<m?0:sub(Calc_C(n+m,m),Calc_C(n+m,m-1)));
}

int main(){
  into();
  work();
  outo();
  return 0;
}

你可能感兴趣的:(BZOJ1856【SCOI2010】字符串题解(组合数学+Catalan数))