UESTC 1712 Easy Problem With Numbers (线段树区间修改+非互素逆元)

题意:

输入n个数与q个操作,以及一个数M.
操作有三种形式:
1.将区间[L,R]内的数都乘以一个数x;
2.将区间[L,R]内的数都除以一个数x;
3.询问区间[L,R]内所有数的乘积模除M的结果。

思路:

这题拖到现在才把它补了。。代码太长又手残GG 。
很裸的线段树和很裸的模运算。。但是结合在一起很是恶心啊。

如果是将区间[L,R]内的数都乘以一个数x,这个很好写,就是线段树的区间修改;
如果是将区间[L,R]内的数都除以一个数x,而这个x还不一定与M互素,无法直接求逆元,这道题的主要考核点其实在这。。

一般在模运算里,除法操作需要求逆元,不互素的两个数是无法得到逆元的,令

M=ps11ps22pskkx=pm11pm22pmkkA

那么 A 与 M 互素,求 A 关于 M 的逆元,其余部分正常除(素数指数上的减法)即可,最后再乘上逆元。
例如 :
4/2mod6,x=2 , M=6 , A=1inv(A,M)=14/x=22/x=22/(21A)=221inv(A,M)modM 4/2=22/2=22/(211)=2211=2mod(2131)

代码:

好长好长。。

//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <functional>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <bitset>

using namespace std;

#define IOS std::ios::sync_with_stdio(false);std::cin.tie(0)
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl
#define pri( x ) cout << #x << " = " << x << " "
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case #%d:\n" , kase++ )
#define mp make_pair
#define pii pair<int,int>
#define pli pair<long long,int>
#define pll pair<long long,long long>
#define fs first
#define se second
#define pb push_back
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
typedef long long lint;
typedef long long LL;
typedef unsigned long long ULL;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;

const int N = 1e4 + 50 ;
lint pro[N<<2] , mul[N<<2] ;
int a[N] , cov[N<<2] , num[N<<2][20] , pnum[N<<2][20] ;
int MOD ;
int cnt ;

lint pow_mod( lint x , lint n , lint mod )
{
    if ( n < 0 ) return 0 ;
    x %= mod ;
    lint res = 1 ;
    while ( n ) {
        if ( n & 1 )
            res = res * x % mod ;
        n >>= 1 ;
        x = x * x % mod ;
    }
    return res ;
}

lint extgcd( lint a , lint b , lint &x , lint &y )
{
    if ( !b ) { x = 1 ; y = 0 ; return a ; }
    lint d = extgcd( b , a % b , y , x ) ;
    y -= x * ( a / b ) ;
    return d ;
}
int fac[100] ;
int getFac( int n )
{
    cls(fac) ;
    int k = 0 ;
    for ( int i = 2 ; i * i <= n ; i++ ) {
        if ( n % i == 0 ) {
            fac[k++] = i ;
            while ( n % i == 0 ) n /= i ;
        }
    }
    if ( n > 1 ) fac[k++] = n ;
    return k ;
}
int facnum[100] ;
void getFactor( int &x , int v )
{
    for ( int i = 0 ; i < cnt ; i++ ) {
        facnum[i] = 0 ;
        if ( x % fac[i] == 0 ) {
            while( x && ( x % fac[i] == 0 ) ) {
                x /= fac[i] ;
                facnum[i] += v ;
            }
        }
    }
}


void push_up( int rt )
{
    for ( int i = 0 ; i < cnt ; i++ ) num[rt][i] = num[rt<<1][i] + num[rt<<1|1][i] ;
    pro[rt] = pro[rt<<1] * pro[rt<<1|1] % MOD ;
}

void push_down( int len , int rt )
{
    if ( cov[rt] ) {
        int ll = len - ( len >> 1 )  , rl = len >> 1 ;
        mul[rt<<1] = mul[rt<<1] * mul[rt] % MOD ;
        mul[rt<<1|1] = mul[rt<<1|1] * mul[rt] % MOD ;
        pro[rt<<1] = pro[rt<<1] * pow_mod( mul[rt] , ll , MOD ) % MOD ;
        pro[rt<<1|1] = pro[rt<<1|1] * pow_mod( mul[rt] , rl , MOD ) % MOD ;
        cov[rt<<1] = cov[rt<<1|1] = cov[rt] ;
        cov[rt] = 0 ;
        mul[rt] = 1 ;
        for ( int i = 0 ; i < cnt ; i++ ) {
            num[rt<<1][i] += pnum[rt][i] * ll ;
            num[rt<<1|1][i] += pnum[rt][i] * rl ;
            pnum[rt<<1][i] += pnum[rt][i] ;
            pnum[rt<<1|1][i] += pnum[rt][i]  ;
            pnum[rt][i] = 0 ;

        }
    }
}
void init( int rt )
{
    cov[rt] = 0 ; mul[rt] = 1 ;
    for ( int i = 0 ; i < cnt ; i++ ) pnum[rt][i] = 0 ;
}
void build( int l , int r , int rt )
{
    init( rt ) ;
    if ( l == r ) {
        getFactor( a[l] , 1 ) ;
        for ( int i = 0 ; i < cnt ; i++ ) num[rt][i] = facnum[i] ;
        pro[rt] = a[l] % MOD ;
        return ;
    }
    int mid = ( l + r ) >> 1 ;
    build( lson ) ;
    build( rson ) ;
    push_up( rt ) ;
}

void update( int ql , int qr , lint x , int l , int r , int rt )
{
    if ( ql <= l && r <= qr ) {
        int len = r - l + 1 ;
        pro[rt] = pro[rt] * pow_mod( x , len , MOD ) % MOD ;
        mul[rt] = mul[rt] * x % MOD ;
        cov[rt] = 1 ;
        for ( int i = 0 ; i < cnt ; i++ ) {
            num[rt][i] += facnum[i] * len ;
            pnum[rt][i] += facnum[i] ;
        }
        return ;
    }
    push_down( r - l + 1 , rt ) ;
    int mid = ( l + r ) >> 1;
    if ( ql <= mid )
        update( ql , qr , x , lson ) ;
    if ( qr > mid )
        update( ql , qr , x , rson ) ;
    push_up( rt ) ;
}

lint query( int ql , int qr , int l , int r , int rt )
{
    if ( ql <= l && r <= qr ) {
        lint tmp = pro[rt] ;
        for ( int i = 0 ; i < cnt ; i++ )
            tmp = tmp * pow_mod( fac[i] , num[rt][i] , MOD ) % MOD ;
        return tmp ;
    }
    push_down( r - l + 1 , rt ) ;
    int mid = ( l + r ) >> 1 ;
    lint res = 1 ;
    if ( ql <= mid )
        res = res * query( ql , qr , lson ) % MOD ;
    if ( qr > mid )
        res = res * query( ql , qr , rson ) % MOD ;
    return res ;
}
int main()
{
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    test(t) {
        int n , q ;
        scanf( "%d%d" ,&n ,&MOD ) ;
        cnt = getFac( MOD ) ;
        for ( int i = 1 ; i <= n ; i++ ) {
            scanf( "%d" , a + i ) ;
        }
        build( 1, n , 1 ) ;
        scanf( "%d" ,&q ) ;
        out( kase ) ;
        for ( int i = 0 ; i < q ; i++) {
            char op[2] ; scanf( "%s" , op ) ;
            if ( op[0] == 'M' ) {
                int L , R , x ;
                scanf( "%d%d%d" , &L , &R , &x ) ;
                getFactor( x , 1 ) ;
                update( L , R , x , 1 , n , 1 ) ;
            }
            else if ( op[0] == 'D' ) {
                int L , R , x ;
                scanf( "%d%d%d" , &L , &R , &x ) ;
                getFactor( x , -1 ) ;
                // pr(x) ;
                lint inv , y ;
                extgcd( x , MOD , inv , y ) ;
                // pr(inv) ;
                inv = ( inv + MOD )  % MOD ;
                update( L , R , inv , 1 , n , 1 ) ;
            }
            else if ( op[0] == 'Q' ) {
                int L , R ;
                scanf( "%d%d" , &L , &R ) ;
                printf( "%lld\n", query( L , R , 1 , n , 1 ) % MOD ) ;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值