Distance
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 304 Accepted Submission(s): 111
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
赛后把题解看了一下,大概懂了意思。
但是自己的代码还是没写出来。
把题解和标程贴一下,供大家一起学习。等我过了再把自己的代码也贴上。
————————————————————————————————————————————————————————————————————————————
不难发现d(a, b) = f(a/gcd(a, b)) + f(b/gcd(a,b)),其中f(x)表示x的质因子个数. 因而当遇到操作Q x时,我们只需要枚举x的每个约数y,看属于当前集合的y的所有倍数z中f(z/y)的最小值为多少. 为了快速求出这个最小值,我们用C[y][s]表示当前集合中y的所有倍数z中使得f(z/y)=s的z的数量.
因为s的值不会超过20,所以可以用位压缩的方法,用D[y]表示y的倍数中哪些s值出现了,这样查询最小的s值可以通过位运算快速求出(因为时限是标程的3倍,所以也不会特意卡掉其它方法). 插入和删除x时同样可以通过枚举x约数的方法来更新C[y][s]和D[y]的值. 设M表示元素的最大值,因为1到M所有约数的数量是O(MlogM)的,所以算法的时间和空间复杂度也都是O(MlogM)的. 又因为操作数少于M,所以实际情况还会更好一些.
#include <cstdio>
#include <cstring>
#include <utility>
#include <vector>
using namespace std;
const int N = 100000 + 10;
const int M = 1000000;
const int inf = 1000000000;
vector<int> V[M+1];
vector< pair<int, int> > F[M+1];
int cnt[M+1], sf[M+1], tb[(1<<21)+1], tmp[M+1], fresh[M+1];
bool flag[M+1];
int D[M+1];
int C[M+1][21];
void init()
{
int i, j;
for (i=1; i<=M; i++) sf[i] = i;
for (i=2; i*i<=M; i++) if (sf[i] == i) for (j=i*i; j<=M; j+=i) if (sf[j] == j) sf[j] = i;
}
int decomp(int x)
{
int s, y, f, i;
if (cnt[x] != -1) return cnt[x];
y = x;
cnt[y] = 0;
while (x > 1)
{
f = sf[x];
s = 0;
do
{
x /= sf[x];
s ++;
}while (x > 1 && sf[x] == f);
F[y].push_back(make_pair(f, s));
cnt[y] += s;
}
return cnt[y];
}
void search(int x, int k, int f)
{
if (k == F[x].size()) V[x].push_back(f);
else
{
search(x, k + 1, f);
for (int i=1; i<=F[x][k].second; i++)
{
f *= F[x][k].first;
search(x, k + 1, f);
}
}
}
void cal(int x)
{
if (V[x].size()) return;
decomp(x);
search(x, 0, 1);
}
int main()
{
int res, q, cn, x, y, z, top, i;
char cmd;
memset(cnt, -1, sizeof(cnt));
init();
for (i=0; i<21; i++) tb[1<<i] = i;
cn = 0;
while (scanf("%d\n", &q), q > 0)
{
printf("Case #%d:\n", ++ cn);
memset(flag, false, sizeof(flag));
top = 0;
while (q --)
{
scanf("%c %d\n", &cmd, &x);
if (cmd == 'I')
{
if (!flag[x])
{
flag[x] = true;
cal(x);
for (i=0; i<V[x].size(); i++)
{
y = V[x][i];
if (fresh[y] != cn)
{
tmp[top++] = y;
fresh[y] = cn;
}
int s = decomp(x / y);
C[y][s] ++;
if (C[y][s] == 1) D[y] ^= (1<<s);
}
}
}
else if (cmd == 'D')
{
if (flag[x])
{
flag[x] = false;
for (i=0; i<V[x].size(); i++)
{
y = V[x][i];
int s = decomp(x / y);
C[y][s] --;
if (C[y][s] == 0) D[y] ^= (1<<s);
}
}
}
else
{
cal(x);
res = inf;
for (i=0; i<V[x].size(); i++)
{
y = V[x][i];
if (!D[y]) continue;
z = tb[D[y]&(-D[y])] + decomp(x / y);
if (z < res) res = z;
}
if (res == inf) printf("-1\n"); else printf("%d\n", res);
}
}
for (i=0; i<top; i++)
{
D[tmp[i]] = 0;
memset(C[tmp[i]], 0, sizeof(C[tmp[i]]));
}
}
return 0;
}
质因数距离问题解析

本文解析了一种基于质因数的整数距离定义,并提供了解决方案,通过高效的算法处理一系列数学运算,如乘除法,以实现特定整数集合上的插入、删除和查询操作。
395

被折叠的 条评论
为什么被折叠?



