J - Master of GCD ( 差分 )

J - Master of GCD ( 差分 )

题目描述:给你一个大小为n的数列,最开始数列的数全都为1。有m次更新,每次输入l,r,c。代表将在数列区间l到r的数成上c。最后求出整个数列gcd。

题目分析:乍一眼看过去,貌似就是一个裸的区间更新线段树维护区间的gcd。但是,很显然,直接维护gcd的操作太过于困难,因此我们退而求其次,因为每次进行的操作都是对2或3进行乘积,因此,我们可以在每次更新的过程中记录区间中2和3的个数,最后用快速幂乘起来算gcd。

因为只需要记录个数,因此,我们可以使用树状数组去维护区间的值。

统计好个数之后,还得注意一个优化:因为gcd的值事实上与2和3出现次数最多的数没有任何影响,只有出现次数最少的数才会对gcd的值有影响。因此我们只需要分别记录下2和3中出现次数最少的数,用快速幂算出他们所对应的值并相乘即是答案。

不会用树状数组用差分也可以

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1002;
const ll mod = 998244353;
int n,m;
int a2[100005]; // 存因子2的个数
int a3[100005]; // 存因子3的个数

ll qpow( ll a, ll n )
{
    ll re = 1;
    while ( n ) {
        if ( n&1 ) {
            re = (re*a)%mod;
        }
        n >>= 1;
        a = (a*a)%mod;
    }
    return re;
}

int main()
{
    int listt;
    cin >>listt;
    while ( listt-- ) {
        cin >> n >> m;
        memset(a2,0,sizeof(a2));
        memset(a3,0,sizeof(a3));
        while ( m-- ) {
            int l,r,op;
            scanf("%d %d %d",&l,&r,&op);
            if ( op==2 ) {
                a2[l] ++;      // 差分思想
                a2[r+1] --;
            }
            else if ( op==3 ) {
                a3[l] ++;
                a3[r+1] --;
            }
        }
        int now2 = 0;
        int ans2 = 0x3f3f3f3f;
        for ( int i=1; i<=n; i++ ) {
            now2 += a2[i];
            ans2 = min(ans2,now2);
        }
        int now3 = 0;
        int ans3 = 0x3f3f3f3f;
        for ( int i=1; i<=n; i++ ) {
            now3 += a3[i];
            ans3 = min(ans3,now3);
        }
        ll ans = qpow(2,ans2);
        ans = (ans*qpow(3,ans3))%mod;
        cout << ans << endl;
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值