zoukankan      html  css  js  c++  java
  • 【SCOI2010】生成字符串

    Description

    给定n,m,求一个包含n个1,m个0,且任何前缀的1的数量必须大于0的数量的合法01串的数量,答案对20100403取模。

    Solution

    我们建立坐标系,定义x坐标为1和0的数量的和,y坐标表示1和0的数量的差,那么向右上走就表示选择1,向右下走就表示选择0。

    如果不考虑限制条件,那么我们要从(0,0)走到(n+m,n-m),就相当于从n+m步中选出m步向右下走,方案数就是$C_{n+m}^m$

    现在考虑限制条件:任何前缀的1的数量必须大于0的数量,那么就意味着我们的在坐标系中的路径不能经过直线y=-1,那么非法的方案就是从(0,0)走到(x,-1)再走到(n+m,n-m),这就等价于从(0,-2)开始走到(n+m,n-m),即方案数为$C_{n+m}^{m-1}$,那么合法方案数就是这两个方案数之差。

    我们首先预处理出一个阶乘数组和一个阶乘的逆元数组,逆元可以通过费马小定理或者是线性递推实现。

    然后套用组合数的公式即可完成。

    Code

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll n, m, fac[2000010], inv[2000010];
     5 const ll mod = 20100403;
     6 inline ll qpow(ll a, ll n) {
     7     ll ret = 1;
     8     while (n) {
     9         if (n & 1) ret = (ret * a) % mod;
    10         a = a * a % mod;
    11         n >>= 1;
    12     }
    13     return ret;
    14 }
    15 inline ll C(ll n, ll m) {
    16     return ((fac[n] * inv[m]) % mod) * inv[n - m] % mod;
    17 }
    18 int main() {
    19     scanf("%lld%lld", &n, &m);
    20     fac[1] = 1;
    21     for (register int i = 2; i <= n + m; ++i) fac[i] = fac[i - 1] * i % mod;
    22     for (register int i = 1; i <= n + m; ++i) inv[i] = qpow(fac[i], mod - 2);
    23     printf("%lld
    ", (C(n + m, m) - C(n + m, m - 1) + mod) % mod);
    24     return 0;
    25 }
    AC Code
  • 相关阅读:
    PHP中无限分类、无限回复评论盖楼的实现方法,thinkphp5.0无限分类实例
    PHP中session详解
    使用thinkPHP做注册程序的实例
    虾米盒子系统开发APP
    angular 使用base64密码加密
    开发中遇到的两种表格文本长度处理,即长文本截断
    树组件使用文件夹图标
    angular实现指定DIV全屏
    JS调用浏览器打印机
    使用blob二进制流的方式下载后台文件
  • 原文地址:https://www.cnblogs.com/shl-blog/p/11295818.html
Copyright © 2011-2022 走看看