思路
首先我们将两种操作分开讨论:
Part 1 加入操作
那么,我们可以用一个数组 \(vis_i = 0/1\) 表示 \(i\) 是 关闭/开启 状态,\(p_i\) 表示因数有 \(i\) 的数。
如果 $vis_x =1 $,说明此机器在之前已经启动过了,输出 Success
。
然后,对 \(x\) 分解质因数,将质因数全部塞进一个集合 \(a\) 里面。
如果对于任意一个 \(i \in |a|\),\(p_i = 0\) 那么表示启动 \(x\) 是合法的,然后更新 \(p_{a_i}\) 为 \(x\),输出 Success
。(注意还需要更新 \(vis_x\))
否则,就随便找到一个 \(p_{a_i} \neq 0\),即可。
Part 2 删除操作
与加入操作同理。
如果 \(vis_x = 0\),说明此机器已经处于关闭状态,输出 Already off
。
然后还是分解质因数,更新 \(p_i\) 的值即可。(注意还需要更新 \(vis_i\) 的值)
时间复杂度为 \(\Theta(n \sqrt n)\)。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 1e5 + 10;
int n,q;
int p[N];
bool vis[N];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
int main(){
n = read();
q = read();
while (q--){
char op[10];
int x;
scanf("%s",op);
x = read();
if (op[0] == '+'){
if (vis[x]) puts("Already on");
else{
int ans = 0,val = x;
bool ok = true;
vector<int> v;
for (re int i = 2;i * i <= x && ok;i++){
if (x % i == 0){
if (p[i]){
ok = false;
if (p[i]) ans = p[i];
else ans = p[x / i];
}
else{
v.push_back(i);
while (x % i == 0) x /= i;
}
}
}
if (x != 1){
if (p[x]){
ok = false;
ans = p[x];
}
else v.push_back(x);
}
if (ok){
vis[val] = true;
for (auto num:v) p[num] = val;
puts("Success");
}
else printf("Conflict with %d\n",ans);
}
}
else{
if (!vis[x]) puts("Already off");
else{
vis[x] = false;
for (re int i = 2;i * i <= x;i++){
if (x % i == 0){
p[i] = 0;
while (x % i == 0) x /= i;
}
}
if (x != 1) p[x] = 0;
puts("Success");
}
}
}
return 0;
}
标签:CF154B,int,题解,更新,vis,质因数,Colliders
From: https://www.cnblogs.com/WaterSun/p/18263297