zoukankan      html  css  js  c++  java
  • Codeforces 895.D String Mark

    D. String Mark
    time limit per test
    4 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    At the Byteland State University marks are strings of the same length. Mark x is considered better than y if string y is lexicographically smaller than x.

    Recently at the BSU was an important test work on which Vasya recived the mark a. It is very hard for the teacher to remember the exact mark of every student, but he knows the mark b, such that every student recieved mark strictly smaller than b.

    Vasya isn't satisfied with his mark so he decided to improve it. He can swap characters in the string corresponding to his mark as many times as he like. Now he want to know only the number of different ways to improve his mark so that his teacher didn't notice something suspicious.

    More formally: you are given two strings ab of the same length and you need to figure out the number of different strings c such that:

    1) c can be obtained from a by swapping some characters, in other words c is a permutation of a.

    2) String a is lexicographically smaller than c.

    3) String c is lexicographically smaller than b.

    For two strings x and y of the same length it is true that x is lexicographically smaller than y if there exists such i, that x1 = y1, x2 = y2, ..., xi - 1 = yi - 1, xi < yi.

    Since the answer can be very large, you need to find answer modulo 109 + 7.

    Input

    First line contains string a, second line contains string b. Strings a, b consist of lowercase English letters. Their lengths are equal and don't exceed 106.

    It is guaranteed that a is lexicographically smaller than b.

    Output

    Print one integer  — the number of different strings satisfying the condition of the problem modulo 109 + 7.

    Examples
    input
    abc
    ddd
    output
    5
    input
    abcdef
    abcdeg
    output
    0
    input
    abacaba
    ubuduba
    output
    64
    Note

    In first sample from string abc can be obtained strings acb, bac, bca, cab, cba, all of them are larger than abc, but smaller than ddd. So the answer is 5.

    In second sample any string obtained from abcdef is larger than abcdeg. So the answer is 0.

    题目大意:给两个字符串a,b,重组a字符串得到c,使得c的字典序大于a小于b,问方案数.

    分析:比较有难度,一开始没能想出来.

              其实这道题有点像数位dp,有上下界嘛,求个数.但是不同的是要求的字符串需要是a重组得到的,每个字符的个数是一定的,也就是说在当前位放了一个数,可能会对后面的决策造成影响.于是就可以用记忆化搜索来解决.

              设f[i][0/1][0/1]表示前i位中是否达到上界和是否达到下界的方案数.类似于数位dp,先处理既达到上界又达到下界的,如果当前处理到第i位并不是只能选一个数字的话,那么可以把这个过程拆成处理到达上界的部分和处理到达下界的部分.如果只能选一个数字,那么这个数字的个数-1,搜下去.再处理上下界的情况.将上下界的数字的个数分别-1,搜下去,这里要分别处理.

              剩下的就是处理位于下界+1和上界-1之间的数了.枚举放哪一个,方案数就是排列数,只不过元素允许重复,需要用不全相异元素的排列公式来计算,即如果总共有n个数,第i个数有ni个,那么方案数为n! / (n1! * n2! * ...... * nn!).最后将所有转移的答案累加就是问题的答案了.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cmath>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 1000010, mod = 1e9 + 7;
    ll f[maxn][2][2], len, a[maxn], b[maxn], num[maxn], jie[maxn];
    char s1[maxn], s2[maxn];
    
    ll qpow(ll a, ll b)
    {
        ll res = 1;
        while (b)
        {
            if (b & 1)
                res = (res * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return res;
    }
    
    ll solve(ll cur, bool up, bool down)
    {
        ll ans = 0;
        if (f[cur][up][down] != -1)
            return f[cur][up][down];
        if (up && down && a[cur] == b[cur] && num[a[cur]] > 0)
        {
            num[a[cur]]--;
            ll temp = solve(cur + 1, up, down);
            num[a[cur]]++;
            return f[cur][up][down] = temp;
        }
        if (up && num[b[cur]])
        {
            num[b[cur]]--;
            ans += solve(cur + 1, 1, 0);
            ans %= mod;
            num[b[cur]]++;
        }
        if (down && num[a[cur]])
        {
            num[a[cur]]--;
            ans += solve(cur + 1, 0, 1);
            ans %= mod;
            num[a[cur]]++;
        }
        ll temp = 1;
        for (ll i = 1; i <= 26; i++)
            temp = (temp * jie[num[i]]) % mod;
        temp = qpow(temp, mod - 2);
        int upx = (up ? b[cur] - 1 : 26), downx = (down ? a[cur] + 1 : 1);
        ll left = len - cur;
        for (ll i = downx; i <= upx; i++)
        {
            if (num[i] > 0)
                ans += jie[left] * temp % mod * num[i] % mod;  //因为num[i]的数量要-1,所以分母的阶乘要减少num[i]
            ans %= mod;
        }
        return f[cur][up][down] = ans;
    }
    
    int main()
    {
        jie[0] = 1;
        for (ll i = 1; i <= 1000000; i++)
            jie[i] = (jie[i - 1] * i) % mod;
        scanf("%s", s1 + 1);
        scanf("%s", s2 + 1);
        len = strlen(s1 + 1);
        for (ll i = 1; i <= len; i++)
        {
            a[i] = s1[i] - 'a' + 1;
            num[a[i]]++;
            b[i] = s2[i] - 'a' + 1;
        }
        memset(f, -1, sizeof(f));
        cout << solve(1,1,1) << endl;
    
        return 0;
    }

              

  • 相关阅读:
    rxjs入门7之其它操作符复习
    rxjs入门6之合并数据流
    rxjs入门5之创建数据流
    rxjs入门4之rxjs模式设计
    boost_1.63.0编译VS2013
    c++基础类型之signed、unsigned的一个细节
    【排序】归并排序算法
    【排序】快速排序算法
    【排序】冒泡排序算法
    【排序】堆排序算法
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8046421.html
Copyright © 2011-2022 走看看