http://acm.hdu.edu.cn/showproblem.php?pid=6273
题目大意:
T
T
T组数据,每组数据
n
n
n个整数,
m
m
m个操作,
n
n
n个整数初始都为
1
1
1,每次操作可以选取一个区间
[
l
,
r
]
[l,r]
[l,r],把这个区间的数都乘上
x
x
x,简单起见,
x
x
x的取值只有
2
、
3
2、3
2、3两种情况,问
m
m
m次操作之后,这
n
n
n个整数的最大公因数。
思路:可以用线段树,但没必要。设第 i i i个数做了 a i a_i ai次乘 2 2 2操作,做了 b i b_i bi次乘 3 3 3操作,显然答案就是 2 m i n ( a i ) ∗ 3 m i n ( b i ) 2^{min(a_i)}*3^{min(b_i)} 2min(ai)∗3min(bi),因此开两个数组分别维护乘 2 2 2操作的次数和乘 3 3 3操作的次数,通过差分把区间修改转换为单点修改,最后遍历取最小值即可,时间复杂度 O ( n ) O(n) O(n),代码量也很小。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#define pr pair<int,int>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=1e5+5;
int a[maxn],b[maxn];
int n,m,t;
ll qpow(int a,int b)//快速幂
{
ll t1=1,t2=a;
while(b)
{
if(b&1)
t1=t1*t2%mod;
t2=t2*t2%mod;
b>>=1;
}
return t1;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int l,r,x;
while(m--)
{
scanf("%d %d %d",&l,&r,&x);
if(x==2)
++a[l],--a[r+1]; //差分操作
else
++b[l],--b[r+1]; //差分操作
}
int MIN1=INF,MIN2=INF;
int tot1=0,tot2=0;
for(int i=1;i<=n;i++)
{
tot1+=a[i],tot2+=b[i];
MIN1=min(MIN1,tot1); //遍历取最小值
MIN2=min(MIN2,tot2);
}
printf("%lld\n",qpow(2,MIN1)*qpow(3,MIN2)%mod);
}
return 0;
}