1. 程式人生 > >[SCOI2010]生成字串

[SCOI2010]生成字串

題目描述

lxhgww最近接到了一個生成字串的任務,任務需要他把n個1和m個0組成字串,但是任務還要求在組成的字串中,在任意的前k個字元中,1的個數不能少於0的個數。現在lxhgww想要知道滿足要求的字串共有多少個,聰明的程式設計師們,你們能幫助他嗎?

輸入輸出格式

輸入格式:

輸入資料是一行,包括2個數字n和m

輸出格式:

輸出資料是一行,包括1個數字,表示滿足要求的字串數目,這個數可能會很大,只需輸出這個數除以20100403的餘數

輸入輸出樣例

輸入樣例#1:

2 2

輸出樣例#1:

2

說明

limitation

每點2秒

對於30%的資料,保證1<=m<=n<=1000

對於100%的資料,保證1<=m<=n<=1000000


題解

一眼組合數

然後想到像catalan數那樣把\(0/1\)轉化到座標系中

然後就越走越偏==

正解是類似Catalan數的推導公式的東西

選1就是\((x,y) -> (x+1,y+1)\)

選0就是\((x,y) -> (x+1,y-1)\)

所以構成\(0/1\)字串的方案數就是\(C(n+m,m)\)

然後有一個條件就是任何時候1的數量都不小於0的數量

所以答案就是從\((0,0)\)出發不碰到\(y=-1\)的路徑

考慮怎麼去掉碰到\(y=-1\)的路徑

我們可以把從\((0,0)\)碰到\(y=-1\)

的直線對稱下來

就是從\((0,-2)\)\(n+m\)步走到\((n,n-m)\)的方案數

所以答案就是走\(n+m+1\)步1,走\(m-1\)步0

#include<cstdio>
#include<iostream>
# define int long long
const int M = 2000005 ;
const int mod = 20100403 ;
using namespace std ;
int n , m ;
int Fac[M] , Ans ;

inline int Fpw(int Base , int k) {
    int temp = 1 ;
    while(k) {
        if(k & 1) temp = (temp * Base) % mod ;
        Base = (Base * Base) % mod ; k >>= 1 ;
    }
    return temp ;
}
inline int C(int n , int m) 
{ return (Fac[n] * Fpw((Fac[m] * Fac[n - m]) % mod , mod - 2)) % mod ; }
# undef int
int main() {
# define int long long
    cin >> n >> m ;
    Fac[0] = 1 ; for(int i = 1 ; i <= n + m ; i ++) Fac[i] = (Fac[i - 1] * i) % mod ;
    cout << (C(n + m , m) - C(n + m , m - 1) + mod) % mod << endl ;
    return 0 ;
}