Live2D

Solution -「多校联训」神

\(\mathcal{Description}\)

  Link.

  给定 \(n\) 阶排列 \(a\)\(q\) 次询问,每次给出 \(1\le l_1\le r_1<l_2\le r_2\le n\)\(r_1-l_1=r_2-l_2\),询问满足 \(\forall j\in[1,r_1-l_1+1],~a_{j+l_1-1}<a_{b_j+l_2-1}\)\((r_1-l_1+1)\) 阶排列 \(b\) 的个数,模 \((10^9+7)\)

  多测,\(\sum n,\sum q\le10^5\)\(a\) 的逆序对数 \(\le10^5\)

\(\mathcal{Solution}\)

  暴力做法:设前后询问区间为 \(A\)\(B\),把两个区间的元素丢一起升序排序,则每个 \(A\) 中元素选择匹配点的方案数为其后方 \(B\) 类元素个数减去 \(A\) 类元素个数。

  将同属一类的连续元素视为一段,那么有结论:段数为 \(\mathcal O(\sqrt n)\) 级别。

每个 \(B\) 段与后方所有 \(A\) 段组成逆序对,故段数与逆序对数是平方关系,而逆序对数是 \(\mathcal O(n)\) 级别,故段数 \(\mathcal O(\sqrt n)\) 级别。

  利用主席数查找前驱快速求出每段长度,即可 \(\mathcal O(n\log n+q\sqrt n\log n)\) 求解。

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <cstdio>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )

const int MAXN = 1e5, MOD = 1e9 + 7;
int n, q, root[MAXN + 5], fac[MAXN + 5], ifac[MAXN + 5];

inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
inline int mpow( int a, int b ) {
    int ret = 1;
    for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
    return ret;
}

inline void init() {
    fac[0] = 1;
    rep ( i, 1, MAXN ) fac[i] = mul( i, fac[i - 1] );
    ifac[MAXN] = mpow( fac[MAXN], MOD - 2 );
    per ( i, MAXN - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );
}

struct SegmentTree {
    static const int MAXND = 2e6;
    int node, ch[MAXND][2], sum[MAXND];

    inline void insert( int& u, const int l, const int r, const int x ) {
        int v = u, mid = l + r >> 1; u = ++node;
        ch[u][0] = ch[v][0], ch[u][1] = ch[v][1], sum[u] = sum[v] + 1;
        if ( l == r ) return ;
        if ( x <= mid ) insert( ch[u][0], l, mid, x );
        else insert( ch[u][1], mid + 1, r, x );
    }

    inline int count( const int u, const int v, const int l, const int r,
      const int ql, const int qr ) {
        if ( !v ) return 0;
        if ( ql <= l && r <= qr ) return sum[v] - sum[u];
        int mid = l + r >> 1, ret = 0;
        if ( ql <= mid ) ret += count( ch[u][0], ch[v][0], l, mid, ql, qr );
        if ( mid < qr ) ret += count( ch[u][1], ch[v][1], mid + 1, r, ql, qr );
        return ret;
    }

    inline int prefix( const int u, const int v, const int l, const int r,
      const int x ) {
        if ( !x || sum[v] <= sum[u] ) return 0;
        if ( l == r ) return l;
        int mid = l + r >> 1;
        if ( x <= mid ) return prefix( ch[u][0], ch[v][0], l, mid, x );
        if ( int t = prefix( ch[u][1], ch[v][1], mid + 1, r, x ); t ) return t;
        return prefix( ch[u][0], ch[v][0], l, mid, x );
    }
} sgt;

int main() {
    freopen( "god.in", "r", stdin );
    freopen( "god.out", "w", stdout );

    int T; init();
    for ( scanf( "%d", &T ); T--; sgt.node = 0 ) {
        scanf( "%d %d", &n, &q );
        rep ( i, 1, n ) {
            int t; scanf( "%d", &t );
            sgt.insert( root[i] = root[i - 1], 1, n, t );
        }

        for ( int l1, r1, l2, r2; q--; ) {
            scanf( "%d %d %d %d", &l1, &r1, &l2, &r2 );
            int rt1[] = { root[l1 - 1], root[r1] },
              rt2[] = { root[l2 - 1], root[r2] };
            int mxl = sgt.prefix( rt1[0], rt1[1], 1, n, n ),
              mxr = sgt.prefix( rt2[0], rt2[1], 1, n, n ), cnt = 0, ans = 1;
            while ( mxl || mxr ) {
                if ( mxl < mxr ) {
                    int lef = sgt.prefix( rt1[0], rt1[1], 1, n, mxr ),
                      len = sgt.count( rt2[0], rt2[1], 1, n, lef, mxr );
                    cnt += len;
                    mxr = sgt.prefix( rt2[0], rt2[1], 1, n, lef );
                } else {
                    int lef = sgt.prefix( rt2[0], rt2[1], 1, n, mxl ),
                      len = sgt.count( rt1[0], rt1[1], 1, n, lef, mxl );
                    if ( cnt < len ) { ans = 0; break; }
                    ans = mul( ans, mul( fac[cnt], ifac[cnt - len] ) );
                    cnt -= len;
                    mxl = sgt.prefix( rt1[0], rt1[1], 1, n, lef );
                }
            }
            printf( "%d\n", ans );
        }
    }
    return 0;
}

posted @ 2021-07-07 22:01  Rainybunny  阅读(60)  评论(0编辑  收藏  举报