CF1422F Boring Queries

\(\text{lcm}\) 的本质是质因子次数的 \(\max\) , 所以只需对每一个质因数考虑贡献

考虑根号分治

  • \(\sqrt{A}\) 以内只有 \(87\) 个质数,可以使用 \(st\) 表解决

  • 除掉小质数后,大于 \(\sqrt{A}\) 的质因子只可能有一个,相当于求

\[\prod_{l \le i \le r} a_i[pre_i < l] \]

其中 \(pre_i\)\(i\) 之前离 \(i\) 最近的等于 \(a_i\) 的位置

可以使用 \(n\) 棵线段树分别维护确定的 \(l\) , 发现相邻 \(l\) 之间只有一位不同,使用主席树即可。

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;

const int MAXN = 1e5 , MAXS = 450 , Mod = 1e9 + 7;
int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; }
int Mul( int x , int y ) { return 1ll * x * y % Mod; }
int Qkpow( int x , int po ) { int p = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) p = Mul( p , x ); return p; }

int prnum , prime[ MAXS + 5 ]; bool vis[ MAXS + 5 ];
void sieve( ) {
    for( int i = 2 ; i <= MAXS ; i ++ ) {
        if( !vis[ i ] ) prime[ ++ prnum ] = i;
        for( int j = 1 ; j <= prnum && 1ll * i * prime[ j ] <= MAXS ; j ++ ) {
            vis[ i * prime[ j ] ] = 1;
            if( i % prime[ j ] == 0 ) break;
        }
    }
}
char mx[ 90 ][ MAXN + 5 ][ 18 ];
int Query( int d , int l , int r ) {
    int k = log2( r - l + 1 );
    return max( mx[ d ][ l ][ k ] , mx[ d ][ r - ( 1 << k ) + 1 ][ k ] );
}

int n , q , a[ MAXN + 5 ] , pre[ MAXN + 5 ] , nxt[ MAXN + 5 ] , pos[ 2 * MAXN + 5 ];

int siz , rt[ MAXN + 5 ];
struct node { int ls , rs , prd; };
struct Segment_Tree {
    node Tree[ 20 * MAXN + 5 ];
    #define ls( x ) Tree[ x ].ls
    #define rs( x ) Tree[ x ].rs
    #define mid ( l + r >> 1 )
    
    void Pushup( int x ) { Tree[ x ].prd = Mul( ls( x ) ? Tree[ ls( x ) ].prd : 1 , rs( x ) ? Tree[ rs( x ) ].prd : 1 ); }
    void Build( int &x , int l = 1 , int r = n ) {
        x = ++ siz;
        if( l == r ) { Tree[ x ].prd = !pre[ l ] ? a[ l ] : 1; return; }
        Build( ls( x ) , l , mid ); Build( rs( x ) , mid + 1 , r );
        Pushup( x );
    }
    void Update( int &x , int pos , int val , int l = 1 , int r = n ) {
        if( pos < l || pos > r ) return; Tree[ ++ siz ] = Tree[ x ]; x = siz;
        if( l == r ) { Tree[ x ].prd = val; return; }
        Update( ls( x ) , pos , val , l , mid ); Update( rs( x ) , pos , val , mid + 1 , r );
        Pushup( x );
    }
    int Prod( int x , int ql , int qr , int l = 1 , int r = n ) {
        if( !x || r < ql || qr < l ) return 1;
        if( ql <= l && r <= qr ) return Tree[ x ].prd;
        return Mul( Prod( ls( x ) , ql , qr , l , mid ) , Prod( rs( x ) , ql , qr , mid + 1 , r ) );
    }
}Tr;

int main( ) {
    sieve();
    scanf("%d",&n);
    for( int i = 1 ; i <= n ; i ++ ) {
        scanf("%d",&a[ i ]);
        for( int j = 1 ; j <= prnum ; j ++ )
            for( ; a[ i ] % prime[ j ] == 0 ; a[ i ] /= prime[ j ] ) mx[ j ][ i ][ 0 ] ++;
    }
    for( int d = 1 ; d <= prnum ; d ++ )
        for( int j = 1 ; j <= 17 ; j ++ )
            for( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
                mx[ d ][ i ][ j ] = max( mx[ d ][ i ][ j - 1 ] , mx[ d ][ i + ( 1 << j - 1 ) ][ j - 1 ] );

    for( int i = 1 ; i <= n ; i ++ ) {
        pre[ i ] = pos[ a[ i ] ]; nxt[ pos[ a[ i ] ] ] = i;
        pos[ a[ i ] ] = i;
    }
    Tr.Build( rt[ 0 ] );
    for( int i = 1 ; i <= n ; i ++ ) {
        rt[ i ] = rt[ i - 1 ];
        if( nxt[ i ] ) Tr.Update( rt[ i ] , nxt[ i ] , a[ nxt[ i ] ] );
    }

    scanf("%d",&q);
    for( int i = 1 , l , r , lst = 0 ; i <= q ; i ++ ) {
        scanf("%d %d",&l,&r); l = ( l + lst ) % n + 1 , r = ( r + lst ) % n + 1;
        if( l > r ) swap( l , r );
        lst = 1;
        for( int d = 1 ; d <= prnum ; d ++ ) lst = Mul( lst , Qkpow( prime[ d ] , Query( d , l , r ) ) );
        lst = Mul( lst , Tr.Prod( rt[ l - 1 ] , l , r ) );
        printf("%d\n", lst );
    }
    return 0;
}
posted @ 2021-08-30 19:29  chihik  阅读(26)  评论(0编辑  收藏  举报