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;
}
原文地址:https://www.cnblogs.com/lkcc/p/7988757.html