CF1422F Boring Queries
阿新 • • 發佈:2021-08-30
#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; }