cf1649 E. Tyler and Strings


题意:

给定长为 n 的序列 a 和长为 m 的序列 b,问将 s 重新排列后能得到多少个不同的字典序小于 b 的序列。

两个序列 a,b 被视为不同当且仅当至少存在一个 i 使得 \(a_i\neq b_i\)

思路:

从左到右,要么选比 \(b_i\) 小的,要么选 \(a_i=b_i\) 并继续

注意这是个多重集排列数,

\[\frac{n!}{cnt_{a_1}!cnt_{a_2}!\cdots} \]

如果拿掉某个数 \(a_i\),就会乘上 \(\frac{cnt_{a_i}}{n}\)

开个树状数组

具体还挺麻烦的。还要注意处理长度不一致的情况

ll n, m, a[N], b[N], cnt[N];

ll jc[N], jcni[N], ni[N];
void init(int n = N-1) {
    jc[0] = 1;
    for(int i = 1; i <= n; i++) jc[i] = jc[i-1] * i % mod;
    jcni[n] = qmi(jc[n], mod-2);
    for(int i = n; i; i--) jcni[i-1] = jcni[i] * i % mod;
    ni[1] = 1;
    for(int i = 2; i <= n; i++) ni[i] = (mod-mod/i) * ni[mod%i] % mod;
}

signed main() {
    iofast;
    init();
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> a[i], add(a[i], 1), cnt[a[i]]++;
    for(int i = 1; i <= m; i++) cin >> b[i];

    ll ans = 0, res = jc[n];
    for(int i = 1; i < N; i++)
        (res *= jcni[cnt[i]]) %= mod;

    for(int i = 1; i <= n; i++) {
        (ans += res * ni[n+1-i] % mod * ask(b[i]-1) % mod) %= mod;
        (res *= cnt[b[i]] * ni[n+1-i] % mod) %= mod;
        if(cnt[b[i]]) cnt[b[i]]--, add(b[i], -1);
        else break;
        if(i == n && n < m) (ans += 1) %= mod;
    }

    cout << ans;
}