CF1648 C. Tyler and Strings (组合数学,线段树) (1900)

https://codeforces.com/problemset/problem/1648/C
题意: 给出两个数列A和B。给A重新排序使得A的字典序小于B。
思路:
image

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define int long long
#define PII pair<int, int>
const int N = 3e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI =  acos(-1.0);
ll F[N], inv[N];
int s[N], t[N], cnt[N];
ll sum_i[N];
struct node {
    ll val, lazy;
}tr[N << 2];
ll qmi ( ll m, ll k ) {
    ll res = 1 % mod;
    while(k) {
        if(k & 1) res = res * m % mod;
        m = m * m % mod;
        k >>= 1;
    }
    return res;
}
void init(int n) {
    inv[0] = F[0] = 1;
    for ( int i = 1; i <= n; ++ i ) F[i] = F[i - 1] * i % mod;
    inv[n] = qmi(F[n], mod - 2);
    for ( int i = n - 1; i >= 1; -- i ) inv[i] = inv[i + 1] * (i + 1) % mod;
}
void pushup(int rt) {
    tr[rt].val = (tr[rt << 1].val + tr[rt << 1 | 1].val) % mod;
}
void push_down(int l, int r, int rt) {
    if(tr[rt].lazy == 1) return;
    tr[rt << 1].lazy = tr[rt << 1].lazy * tr[rt].lazy % mod;
    tr[rt << 1 | 1].lazy = tr[rt << 1 | 1].lazy * tr[rt].lazy % mod;
    tr[rt << 1].val = tr[rt << 1].val * tr[rt].lazy % mod;
    tr[rt << 1 | 1].val = tr[rt << 1 | 1].val * tr[rt].lazy % mod;
    tr[rt].lazy = 1;
}
void build(int l, int r, int rt) {
    tr[rt].lazy = 1;
    if(l == r) {
        tr[rt].val = sum_i[l] % mod;
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}
ll query( int a, int b, int l, int r, int rt ) {
    if( b < l || a > r ) return 0;
    if( a <= l && b >= r ) {
        return tr[rt].val;
    }
    int mid = l + r >> 1;
    push_down(l, r, rt);
    return (query(a, b, l, mid, rt << 1) + 
    query(a, b, mid + 1, r, rt << 1 | 1)) % mod;
}
void mul(int a, int b, ll val, int l, int r, int rt) {
    if( b < l || a > r ) return;
    if( a <= l && b >= r ) {
        tr[rt].val %= mod;
        tr[rt].val = tr[rt].val * val % mod;
        tr[rt].lazy %= mod;
        if(!tr[rt].lazy) tr[rt].lazy = 1;
        tr[rt].lazy = tr[rt].lazy * val % mod;
        return;
    }
    int mid = l + r >> 1;
    push_down(l ,r, rt);
    mul(a, b, val, l, mid, rt << 1);
    mul(a, b, val, mid + 1, r, rt << 1 | 1);
    pushup(rt);
}
signed main() {
    IOS

    init(200003);
    int n, m; cin >> n >> m;
    for ( int i = 1; i <= n; ++ i ) cin >> s[i], ++ cnt[s[i]];
    for ( int i = 1; i <= m; ++ i ) cin >> t[i];
    ll sum = F[n - 1];
    for ( int i = 1; i <= 200000; ++ i ) if(!cnt[i]) continue; else sum = sum * inv[cnt[i]] % mod;
    for ( int i = 1; i <= 200000; ++ i ) if(!cnt[i]) continue; else sum_i[i] = sum * cnt[i] % mod;
    build(1, 200000, 1);
    bool ok = 0; ll ans = 0, allcnt = n - 1;
    int mm = min(n , m);
    for ( int i = 1; i <= mm; ++ i ) {
        if(t[i] != 1) ans = (ans + query(1, t[i] - 1, 1, 200000, 1)%mod) % mod;
        if(i == mm) { ok = 1; break; } 
        if(!cnt[t[i]]) break;
        mul(1, 200000, cnt[t[i]] * qmi(allcnt, mod - 2) % mod, 1, 200000, 1);
        mul(t[i], t[i], (cnt[t[i]] - 1) * qmi(cnt[t[i]], mod - 2) % mod, 1, 200000, 1);
        -- allcnt; -- cnt[t[i]];
    }
    if(ok && n < m)  ans = (ans + query(t[n], t[n], 1, 200000, 1)% mod) % mod;
    cout << ans << '\n';
    return 0;
}
posted @ 2022-04-12 15:21  qingyanng  阅读(40)  评论(0编辑  收藏  举报