- 问题很直观,因为一个数的质因子个数很少,而且数字个数和查询次数都是
1
0
4
10^4
104级别,所以考虑直接莫队暴力
- 此题是经典莫队,使用两个数组分别记录每个质因子的出现次数和出现次数为
i
i
i的质因子数量,方便统计答案,每当查询的时候,注意左右端点的移动对这两个数组的影响
- 实测采用基本的排序方式也就是左端点按块从小到大,如果相同则按右端点从小到大排序即可通过;但是如果使用优化的排序方式即左端点所在块为奇数按右端点从小到大(同为奇数则按照块的顺序从小到大),否则按照右端点从大到小这种排序方式能快
80
m
s
80ms
80ms左右,后者更优
- 如果使用
n
n
n\sqrt n
nn
的埃筛预处理出所有的质因子会
T
T
T掉,这里选择使用求质因子最简单的办法,就是欧拉函数用的那个,求第
i
i
i个数字的质因子都是谁,这样就不会
T
T
T掉,就很玄学
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
vector<int> fac[N];
int num[N];
int cnt[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--){
int n, q;
cin >> n >> q;
vector<int> a(n + 1), belong(n + 1);
int block = sqrt(n);
for(int i=1;i<=n;i++){
cin >> a[i];
belong[i] = (i - 1) / block + 1;
fac[i].clear();
int x = a[i];
for(int j=2;1ll*j*j<=1ll*x;j++){
if(x % j == 0){
while(x % j == 0){
x /= j;
}
fac[i].push_back(j);
}
}
if(x > 1) fac[i].push_back(x);
}
vector<array<int, 3> > ask(q);
for(int i=0;i<q;i++){
cin >> ask[i][0] >> ask[i][1];
ask[i][2] = i;
}sort(ask.begin(), ask.end(), [&](array<int, 3> x, array<int, 3> y){
return (belong[x[0]] ^ belong[y[0]]) ? belong[x[0]] < belong[y[0]] : ((belong[x[0]] & 1) ? x[1] < y[1] : x[1] > y[1]);
});
vector<int> ans(q);
int res = 0;
function<void(int)> ADD = [&](int x){
for(auto j : fac[x]){
cnt[num[j]] -= 1;
num[j] += 1;
cnt[num[j]] += 1;
res = max(res, num[j]);
}
};
function<void(int)> SUB = [&](int x){
for(auto j : fac[x]){
cnt[num[j]] -= 1;
if(cnt[num[j]] == 0 && num[j] == res){
res -= 1;
}
num[j] -= 1;
cnt[num[j]] += 1;
}
};
int l = 1;
int r = 0;
for(int i=0;i<q;i++){
while(l > ask[i][0]) ADD(--l);
while(r < ask[i][1]) ADD(++r);
while(l < ask[i][0]) SUB(l++);
while(r > ask[i][1]) SUB(r--);
ans[ask[i][2]] = res;
}
for(int i=0;i<q;i++){
cout << ans[i] << '\n';
}
while(l <= r){
SUB(l);
l += 1;
}
}
return 0;
}