Live2D

Solution -「多校联训」神

Description

  Link.

  给定 n 阶排列 aq 次询问,每次给出 1l1r1<l2r2nr1l1=r2l2,询问满足 j[1,r1l1+1], aj+l11<abj+l21(r1l1+1) 阶排列 b 的个数,模 (109+7)

  多测,n,q105a 的逆序对数 105

Solution

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

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

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

  利用主席数查找前驱快速求出每段长度,即可 O(nlogn+qnlogn) 求解。

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 @   Rainybunny  阅读(61)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示