乱搞?????又是?????
Address
https://begin.lydsy.com/JudgeOnline/upload/201805.pdf
Solution
发现好多人用主席树
这里讲一种跑得更快的离线做法。
首先,对于每个询问
(l,r,d)
(
l
,
r
,
d
)
,可以将
d
d
分解质因数。
如果分解的结果是 ,并且质因子
x
x
在 内所有数中出现的次数之和为
sum[l,r,x]
s
u
m
[
l
,
r
,
x
]
,那么询问转化为,判断是否满足:
尝试把每个数进行质因数分解(由于有多组数据,因此可以预处理出 [1,105] [ 1 , 10 5 ] 内所有数的质因数分解以提高效率,而一个 [1,105] [ 1 , 10 5 ] 的质因子个数不超过 6 6 )
把询问 拆成 sum[1,l−1,x] s u m [ 1 , l − 1 , x ] 和 sum[1,r,x] s u m [ 1 , r , x ] 。
于是询问再次转化:求一个前缀内,质因子 x x 的出现次数。
但可以发现,如果对于每个质因子都维护一个前缀和,那么空间是 的,开不下。
于是将询问离线,按照前缀的长度(末尾标号)从小到大排序。
用一个指针 i i 将序列从左到右扫描一遍,扫描的过程中,维护前缀 内各个因子的出现次数。这样,当 i=k i = k 的时候,就能立即回答形如 sum[k,x] s u m [ k , x ] 的询问。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5, M = N << 1, E = 10;
int n, m, w, a[N], tot, pri[N], pr[N], num[N][E], pw[N][E], qn[N], cnt[N],
ans[N][E]; bool mark[N]; struct cyx {int i, id;} q[M];
inline bool comp(const cyx &a, const cyx &b) {return a.i < b.i;}
void sieve() {
int i, j; mark[0] = mark[1] = 1; For (i, 2, 100000) {
if (!mark[i]) pri[++tot] = i; For (j, 1, tot) {
if (1ll * i * pri[j] > 100000) break; mark[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
For (i, 1, 100000) {
int x = i; For (j, 1, tot) {
int y = pri[j]; if (1ll * y * y > i) break;
if (x % y) continue; num[i][++pr[i]] = y;
while (x % y == 0) pw[i][pr[i]]++, x /= y;
}
if (x > 1) num[i][++pr[i]] = x, pw[i][pr[i]] = 1;
}
}
void work() {
int i, j, l, r; n = read(); m = read(); For (i, 1, n) a[i] = read(); w = 0;
For (i, 1, m) {
For (j, 1, 6) ans[i][j] = 0; l = read(); r = read(); qn[i] = read();
q[++w] = (cyx) {l - 1, w - 1}; q[++w] = (cyx) {r, w - 1};
}
sort(q + 1, q + w + 1, comp); memset(cnt, 0, sizeof(cnt)); l = 1;
For (i, 0, n) {
if (i) For (j, 1, pr[a[i]]) cnt[num[a[i]][j]] += pw[a[i]][j];
while (l <= w && q[l].i == i) {
int id = (q[l].id >> 1) + 1; For (j, 1, pr[qn[id]])
if (q[l].id & 1) ans[id][j] += cnt[num[qn[id]][j]];
else ans[id][j] -= cnt[num[qn[id]][j]]; l++;
}
}
For (i, 1, m) {
double res = 1; For (j, 1, pr[qn[i]])
res = res && ans[i][j] >= pw[qn[i]][j]; puts(res ? "Yes" : "No");
}
}
int main() {
int T = read(); sieve(); while (T--) work(); return 0;
}