codeforces 895D

(組み合わせ論)
質問の意味:英語の文字から成る2つの文字列を考えます S1 S2 辞書的に確認してください S1< S2 、どのように多くの検索 S3 だから S1< S3< S2 S3 あります S1 文字からなる配列。

アイデア:
  まず、統計 S1 文字の文字列がどのようなものがあり、それぞれの文字は数回表示され、num個の配列によって保存します。だから我々は、少なくともS3の文字を構成するものを知っていること。それから私は私が最初よりも辞書式順序を数えることができると思いました S1 次いで、少数列、および辞書の比率を算出します S2 小さな文字列の数、マイナスの2つの結果は、答えです。
  最初の数字は直接得られ、より良い要件であります S1 それはすることができ、それ自体整列いくつかの最初のものです。 S3 しないことであるため S1 私は、私は可能と考えていたので、少し難しくから変換 S3 変換後に S1 フォームレター、次いで同じ方法要件による。
  いくつかの最初に自身がして、プロセスを求めて並びます トラバーサル 0 リットルのE N 順次取得:比較結果から、現在位置は、辞書文字列の数未満であります S1 そして、それぞれの 現在の位置の結果を決定するために(ここで置換知識+小さな最適化を使用します)。最後に、答えを追加します。

(書くの式が面倒。これエディタが...。少し言葉を使用する、またはタイトルをノックし、このトピックやアイデア出しが遅く、泥棒をノック)

コード:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long

using namespace std;
const int maxn = 1000010;
const LL mod = 1e9 + 7;

bool s2_smaller, s2_bigger;
int num[30], sum[30];
char s1[maxn], s2[maxn];
LL fac[maxn], inv_fac[maxn];

LL pow(LL a, LL b) {
    LL ret = 1;
    while(b) {
        if(b&1)
            ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}

void pre_treat(int len) {
    fac[0] = inv_fac[0] = 1;
    for(int i=1; i<=len; i++) {
        fac[i] = (LL)i * fac[i-1] % mod;
        inv_fac[i] = pow((LL)fac[i], mod-2);
    }
}

void init(int len) {
    for(int i=0; i<len; i++)
        num[s1[i]-'a'] ++;
    sum[0] = num[0];
    for(int i=1; i<26; i++)
        sum[i] = sum[i-1] + num[i];
}

void transform_s2(int len) {
    init(len);
    for(int i=0; i<len; i++) {
        int alpha = s2[i] - 'a';
        if(!s2_smaller && !s2_bigger) {
            if(num[alpha])
                num[alpha] --;
            else {
                for(int j=alpha-1; j>=0; j--) if(num[j]) {
                    s2_smaller = true; //puts("small");
                    s2[i] = j + 'a'; num[j] --;
                    break ;
                }
                if(s2_smaller) continue ;
                for(int j=alpha+1; j<26; j++) if(num[j]) {
                    s2_bigger = true; //puts("big");
                    s2[i] = j + 'a'; num[j] --;
                    break ;
                }
                if(s2_bigger) continue ;
            }
        }
        else if(s2_smaller) {
            for(int j=25; j>=0; j--) if(num[j]) {
                s2[i] = j + 'a'; num[j] --;
                break ;
            }
        }
        else {//s2_bigger
            for(int j=0; j<26; j++) if(num[j]) {
                s2[i] = j + 'a'; num[j] --;
                break ;
            }
        }
    }
}

LL solve(char *s, int len) {
    init(len);
    LL ret = 0;
    for(int i=0; i<len; i++) {
        int alpha = s[i] - 'a';
        if(alpha > 0 && sum[alpha-1] > 0) {
            LL t1 = fac[len-i-1], t2 = 0;
            for(int j=0; j<26; j++) if(num[j]) {
                t1 = t1 * inv_fac[num[j]] % mod;
                if(j < alpha)
                    t2 = (t2 + num[j]) % mod;
            }
            ret = (ret + t1 * t2 % mod) % mod;
        }
        //printf("------i:%d ret:%I64d\n",i,ret);
        num[alpha] --;
        for(int j=alpha; j<26; j++)
            sum[j] --;
    }
    return ret;
}

int main() {
    //freopen("test.txt","r",stdin);
    s2_smaller = s2_bigger = false;
    scanf("%s%s",s1,s2);
    int len = strlen(s1);
    pre_treat(len);
    transform_s2(len);
    LL l = solve(s1, len), r = solve(s2, len);
    //printf("l:%I64d r:%I64d\n",l,r);
    LL ans = (r - l + mod) % mod;
    if(!s2_smaller && !s2_bigger)
        ans = (ans - 1 + mod) % mod;
    else if(s2_smaller)
        ans = ans;
    else
        ans = (ans - 1 + mod) % mod;
    printf("%I64d\n",ans);
    return 0;
}
公開された40元の記事 ウォン称賛44 ビュー90000 +

おすすめ

転載: blog.csdn.net/Site1997/article/details/78693179