zoukankan      html  css  js  c++  java
  • codeforces 895D

    http://codeforces.com/contest/895/problem/D

    题意:给你二个等长 ( len <= 1e6 ) 字符串 a, b, 并且 a 的 字典序比 b 小, 让你构造字符串 c , 问 c 的情况有多少种 (mod 1e9+7)

       要求:1. c 的字母组成 和 a 一样

          2. a 的字典序比 c 小

          3. c 的字典序比 b 小

    题解:由于题目要求的是 c 的组合有多少种,那可以先求出 c 的排列,再除以每个字母个数的阶乘积即可

       求比字符串 b 字典序小的排列个数, 

         dfs( id, b) 表示 c[ 1~(id-1) ] = b [ 1~(id-1) ] 情况下,比 b 字典序小的有多少 

           那么 若 c[id] = b[id]  取和字符 b[id] 相等的一个,问题就转化成 dfs(id+1, b)

           若 c[id] < b[id]  取比字符 b[id] 小的一个,剩下的字符全排列 

              若 c[id] > b[id] 则 c 的字典序比 b 的大,舍去

    long long dfs(int id, string s) //递归爆栈 MLE 
    {
        if( id >= s.size() ) return 0;
        long long ans = 0;
        if(num[s[id]-'a'])
        {
            --num[s[id]-'a'];
            ans = dfs(id+1, s) * (++num[s[id]-'a']) % mod;
        }
        long long k = sum(s[id]-'a');
        return (ans + k * A[ s.size()-id-1 ] % mod) % mod;
    }

      很难受的是递归调用爆栈了,于是模拟递归写了下

    long long sta[MAXN];
    long long dfs(string s) //  模拟栈 
    {
        memset(sta, 0x00, sizeof(sta));
        int i = 0;
        while( i < s.size() && num[s[i]-'a'] ) 
            --num[s[i]-'a'], ++i;
        if( i < s.size() )
        {
            long long k = sum(s[i]-'a');
            sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod;
        }
        while( --i >= 0 )
        {
            sta[i] = (++num[s[i]-'a']) * sta[i+1] % mod;
            long long k = sum(s[i]-'a');
            sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod;
        }
        return sta[0];
    }

       AC代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define mod 1000000007
    using namespace std;
    const int MAXN = 1000000+10;
    long long A[MAXN];
    int num[26];
    void init()
    {
        A[0] = 1;
        for(int i = 1; i < MAXN; ++i) 
            A[i] = A[i-1]*i%mod;
        memset(num, 0x00, sizeof(num));
    }
    int sum(int k)
    {
        int ans = 0;
        for(int i = 0; i < k; ++i)
            ans += num[i];
        return ans; 
    }
    long long dfs(int id, string s) //递归爆栈 MLE 
    {
        if( id >= s.size() ) return 0;
        long long ans = 0;
        if(num[s[id]-'a'])
        {
            --num[s[id]-'a'];
            ans = dfs(id+1, s) * (++num[s[id]-'a']) % mod;
        }
        long long k = sum(s[id]-'a');
        return (ans + k * A[ s.size()-id-1 ] % mod) % mod;
    }
    long long sta[MAXN];
    long long dfs(string s) //  模拟栈 
    {
        memset(sta, 0x00, sizeof(sta));
        int i = 0;
        while( i < s.size() && num[s[i]-'a'] ) 
            --num[s[i]-'a'], ++i;
        if( i < s.size() )
        {
            long long k = sum(s[i]-'a');
            sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod;
        }
        while( --i >= 0 )
        {
            sta[i] = (++num[s[i]-'a']) * sta[i+1] % mod;
            long long k = sum(s[i]-'a');
            sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod;
        }
        return sta[0];
    }
    long long silimar()
    {
        long long ans = 1;
        for(int i = 0; i < 26; ++i)
            ans = ans * A[num[i]] % mod;
        return ans;
    }
    long long ex(long long x, long long n) //return  x^n
    {
        long long sum = 1;
        x %= mod;
        while(n)
        {
            if( n&1 ) sum *= x, sum %= mod;
            n /= 2;
            x *= x;
            x %= mod;
        }
        return sum;
    }
    int main (void)
    {
        init();
        string a, b, c;
        cin >> a >> b;
        for(int i = 0; i < a.size(); ++i) 
            ++num[ a[i]-'a' ];
    //    long long ans = dfs(0, b) - dfs(0, a); //递归爆栈 MLE
        long long ans = dfs( b ) - dfs( a ); //  模拟栈 
        long long k = silimar();
        ans = ans * ex(k, mod-2) % mod;
        cout << ( ans - 1 + mod ) % mod;
        return 0;
    }
  • 相关阅读:
    关于Javascript的有趣的3个小知识
    linux支持串口(serial)登录配置方法
    Silicom Linux BypassSD Control Utilitybypass command
    USB隨身碟版的Clonezilla live
    如何將Clonezilla live放到一個已經有其他作業系統存在的硬碟中
    clonezilla for usb as ghost or backup,auto ghost,auto backup(再生龙一键还原(备份)的制作)
    典型PC机上各种操作的近似时间
    linux网络问题子网掩码与网关不在同一段的处理
    Linux family member.(AS/ES/WS)
    华为交换机常用命令
  • 原文地址:https://www.cnblogs.com/lkcc/p/7988757.html
Copyright © 2011-2022 走看看