Distance
Total Submission(s): 216 Accepted Submission(s): 81
For a set S of positive integers, which is initially empty, you are asked to implement the following types of operations on S.
1. I x: Insert x into S. If x is already in S, just ignore this operation.
2. D x: Delete x from S. If x is not in S, just ignore this operation.
3. Q x: Find out a minimum z such that there exists a y in S and d(x, y) = z.
Q = 0 indicates the end of the input.
The total number of operations does not exceed 300000.
12 I 20 I 15 Q 30 I 30 Q 30 D 10 Q 27 I 15 D 15 D 20 D 30 Q 5 0
Case #1: 1 0 3 -1
题目大意:
定义两个整数x,y之间的距离d(x,y)为x转换为y的操作数,操作是指乘或除素数。
譬如 15转换为50需要
/3 ∗2 ∗5
三种操作。
然后有如下三种操作
I x 表示向当前集合S中加入x,如果集合S存在x,忽略此次操作。
D x 表示删除集合S中的x,如果集合S中不存在x,忽略此次操作。
Q x 表示查询对于集合S中的整数y,d(x,y)的最小值,如果S为空,输出-1。
转换的思想比较巧妙。
把查询和插入的数,都转换为约数。
这样对于每次查询x,可以遍历x的所有约数,此时x到某个约数
y
的距离为
对于集合中的每个数x,也一样,到每个约数
y
的距离为
因为距离很小,最多20(10^6)内的数,拆分素因子个数不超20
这样可以定义数组
C[y][s]
表示集合S中的所有数,到y的距离为s的数的个数。
这样每次插入一个数x时,遍历x的所有约数y,
C[y][cnt[x/y]]++
查询一个数x时,遍历x的所有约数y,查找的就是 min(cnt[x/y]+C[y][s]中非0的位置的最小的s)
然后就是求约数的问题。预处理很爆炸。并且操作也没到
106
所以可以在三种操作过程中拆分。
标称中一个巧妙的做法是把 106 内每个数中的素数存下来到 f[] 中,只存一个素因子就可以,任意一个。
这样查询x的约数时,用x不断除 f[x] ,然后可以求出x中 f[x] 的个数,除后的余数 x′ 又会有一个新的 f[x′] ,这些统计下来都是 x <script type="math/tex" id="MathJax-Element-2447">x</script>中的素因子。
然后求约数用dfs就行,x中的素因子排列组合。
素材都有了,拼接起来就A啦
代码如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
//#define Debug
using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 1e6;
const int mod = 1e9+7;
const double eps = 1e-8;
bool Isprim[msz+1];
bool vis[msz+1];
int p[msz+1];
int f[msz+1],cnt[msz+1];
int C[msz+1][22],D[msz+1];
int low[1<<22];
vector <int> ys[msz+1];
vector <Pr> sy[msz+1];
int tp;
void init()
{
memset(Isprim,0,sizeof(Isprim));
cnt[1] = 0;
for(int i = 0; i <= 20; ++i)
low[1<<i] = i;
tp = 0;
for(int i = 2; i <= msz; ++i)
{
if(!Isprim[i])
{
p[tp++] = i;
f[i] = i;
cnt[i] = 1;
}
for(int j = 0; j < tp && p[j]*i <= msz; ++j)
{
f[p[j]*i] = p[j];
cnt[p[j]*i] = cnt[p[j]]+cnt[i];
Isprim[p[j]*i] = 1;
if(i%p[j] == 0) break;
}
}
}
void cal(int x)
{
int pos = x;
int c,tmp;
#ifdef Debug
printf("solve:%d\n",x);
#endif
while(x > 1)
{
c = 0;
tmp = f[x];
while(x%tmp == 0)
{
x /= tmp;
c++;
}
#ifdef Debug
printf("prim:%d cnt:%d\n",tmp,c);
#endif
sy[pos].push_back(Pr(tmp,c));
}
#ifdef Debug
puts("------");
#endif
}
void solve(int x,int k,int f)
{
if(k == sy[x].size()) ys[x].push_back(f);
else
{
solve(x,k+1,f);
for(int i = 0; i < sy[x][k].second; ++i)
{
f *= sy[x][k].first;
solve(x,k+1,f);
}
}
}
void Insert(int x)
{
if(vis[x]) return;
vis[x] = 1;
if(!sy[x].size()) cal(x);
if(!ys[x].size()) solve(x,0,1);
int y;
#ifdef Debug
printf("%d:\n",x);
#endif
for(int i = 0; i < ys[x].size(); ++i)
{
y = ys[x][i];
if(!C[y][cnt[x/y]])
{
D[y] ^= (1<<cnt[x/y]);
#ifdef Debug
printf("Change! %d:%d\n",y,D[y]);
#endif
}
#ifdef Debug
printf("%d<-%d %d\n",x,y,cnt[x/y]);
#endif
C[y][cnt[x/y]]++;
}
#ifdef Debug
puts("//");
#endif
}
void Delete(int x)
{
if(!vis[x]) return;
vis[x] = 0;
#ifdef Debug
printf("%d:",x);
#endif
for(int i = 0; i < ys[x].size(); ++i)
{
int y = ys[x][i];
#ifdef Debug
printf("%d ",y);
#endif
C[y][cnt[x/y]]--;
if(!C[y][cnt[x/y]]) D[y] ^= (1<<cnt[x/y]);
}
#ifdef Debug
puts("//");
#endif
}
int Lowbit(int x)
{
return x&(-x);
}
int Query(int x)
{
if(!sy[x].size()) cal(x);
if(!ys[x].size()) solve(x,0,1);
int ans = -1;
#ifdef Debug
printf("Query %d:\n",x);
#endif
for(int i = 0; i < ys[x].size(); ++i)
{
int y = ys[x][i];
if(!D[y]) continue;
int tmp = cnt[x/y];
#ifdef Debug
printf("%d->%d: %d\n",x,y,tmp);
#endif
tmp += low[Lowbit(D[y])];
#ifdef Debug
printf("MIN%d: %d\n",y,Lowbit(D[x/y])>>1);
#endif
if(ans == -1 || ans > tmp) ans = tmp;
}
#ifdef Debug
puts("//");
#endif
return ans;
}
int main()
{
//fread("");
//fwrite("");
init();
int q,x,z = 1;
char opt[3];
while(~scanf("%d",&q) && q)
{
memset(vis,0,sizeof(vis));
memset(C,0,sizeof(C));
memset(D,0,sizeof(D));
printf("Case #%d:\n",z++);
while(q--)
{
scanf("%s%d",opt,&x);
if(opt[0] == 'I') Insert(x);
else if(opt[0] == 'D') Delete(x);
else printf("%d\n",Query(x));
}
}
return 0;
}