zoukankan      html  css  js  c++  java
  • bzoj1856: [Scoi2010]字符串

    1856: [Scoi2010]字符串

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 1301  Solved: 719
    [Submit][Status][Discuss]

    Description

    lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?

    Input

    输入数据是一行,包括2个数字n和m

    Output

    输出数据是一行,包括1个数字,表示满足要求的字符串数目,这个数可能会很大,只需输出这个数除以20100403的余数

    Sample Input

    2 2

    Sample Output

    2

    HINT

    【数据范围】
    对于30%的数据,保证1<=m<=n<=1000
    对于100%的数据,保证1<=m<=n<=1000000

    Source

    分析:如果题目仅仅给出了例如n,m的几个大数据,让你求几乎“毫不相干”的数据,那么可能就要用到递推或者公式(也就是数学方法啦).这道题感觉可以用dp做,但是时间承受不了,而能神奇地降低时间复杂度的也就只有数学方法了.         
              如果直接用数学方法做看起来并不好做,转换一下,在一个平面直角坐标系中,从点(0,0)到点(n + m,n - m),一个1相当于从(0,0)向(1,1)的方向走,一个0相当于(0,0)向(1,-1)的方向走,同时不能走到直线y = -1上,可以证明,如果要走n个1,m个0必然要走到(n + m, n - m),求方案数,可以想到用dp或者直接组合数搞起,先考虑没有限制条件的,可以发现n个1是必须取完的一共要取n + m个数,那么要在n + m个数中取n个数,自然方案数就是C(n + m,n),符合条件的方案数=总方案数-不符合条件的方案数,那么我们求出不符合条件的方案数,怎么求呢?可以想象一下把直线y = -1上面的翻折下来,即从点(0,-2)到点(n + m, n - m)经过直线y = -1的方案数,显而易见,肯定经过直线y=-1,关键就是怎么求方案数,走到(n+m,n-m)需要向上走n-m+2次,一共要走n+m次。设向上向下各走x,y,那么x+y=n+m,x-y=n-m+2得到x=n+1,y=m-1,所以不合法的方案为C(n+m,n + 1)。然后就是求组合数的过程.因为组合数只需要用到1次,显然不需要递推,那么就直接算,但是要涉及到取模,除法取模运算不成立!怎么办?用逆元!若,b*b1 % c == 1则,b1称为b模c的乘法逆元。 ( a/b ) % c == ( a*b1 ) % c ,那么问题就是怎么求b1, -k*c + b*b1 == 1,不是扩展欧几里得算法吗?那么直接算就好了.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const int mod = 20100403;
    long long ans;
    int n, m;
    
    void exgcd(long long a, long long b, long long & x, long long &y)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
        }
        else
        {
            exgcd(b, a%b, x, y);
            long long t = x;
            x = y;
            y = t - a / b * y;
        }
    }
    
    long long niyuan(long long a, long long p)
    {
        long long x, y;
        exgcd(a, p, x, y);
        x = (x + mod) % mod;
        return x;
    }
    
    long long Sum(long long x)
    {
        long long temp = 1;
        for (int i = 1; i <= x; i++)
        {
            temp = (temp * i) % mod;
        }
        return temp;
    }
    
    long long C(long long x, long long y)
    {
        long long a, b, c;
        a = Sum(x);
        b = Sum(y);
        c = Sum(x - y);
        return a * niyuan(b, mod) % mod * niyuan(c, mod) % mod;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        ans = (C(n + m, n) - C(n + m, n + 1) + mod) % mod;
        printf("%lld", ans);
    
        return 0;
    }
  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5785553.html
Copyright © 2011-2022 走看看