您的位置:首页 > 其它

HDU - 5812 Distance 数学 + 思维

2017-09-16 21:50 246 查看
传送门:HDU 5812

题意:给出一个空集合和三个操作。操作I向集合中插入元素X,操作D删除集合中的元素X,操作Q,查询集合中的所有元素与X的最小距离是多少? 

定义最小距离 d(x,y) 为从x变为y只通过乘或者除素数所需要的最少操作次数。例如:d(15,50)=3,因为 15/3×2×5=50


思路:首先解题的关键是要知道: d(x,y)=f(x/gcd(x,y))+f(y/gcd(x,y)) 

其实这一点仔细想想也不是很难理解。

然后考虑如何进行查询操作,很显然我们要枚举x的约数i(也就是gcd(x,y)),然后求集合中所有i的倍数y的f(y
/ i)的最小值,f[]数组我们可以预处理出来,集合的话我们可以用mulset s[i]  表示i的倍数的f值,然后每次用i的时候从s[i]里取出第一个来就行了。




更快的方法是维护一个数组:用C[y][s]表示当前集合中y的所有倍数z中使得f(z/y)=s的z的数量. 因为s的值不会超过20,所以可以用位压缩的方法,用D[y]表示C[y][]中哪些s值出现了,这样查询最小的s值可以通过位运算快速求出. 插入和删除x时同样可以通过枚举x约数的方法来更新C[y][s]和D[y]的值. 

代码:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN = 1000010;
int cnt[MAXN];//cnt[i] := i的质因子个数
bool isprime[MAXN];
void init()
{
int tmp;
memset(isprime, 1, sizeof(isprime));
isprime[0] = isprime[1] = 0;
for(int i = 2; i < MAXN; i++)
{
if(!isprime[i]) continue;
cnt[i]++;
for(int j = i + i; j < MAXN; j += i)
{
isprime[j] = 0;
tmp = j;
while(tmp % i == 0)
cnt[j]++, tmp /= i;
}
}
}
multiset<int> s[MAXN];
multiset<int>::iterator it;
bool book[MAXN];
void add(int i, int x)
{
s[i].insert(x);
}
void del(int i, int x)
{
it = s[i].find(x);
if(it != s[i].end())
s[i].erase(it);
}
int query(int i)
{
if(s[i].empty()) return inf;
return *s[i].begin();
}
int main()
{
int x, y, num, q, ans, i, kase = 1;
char ch;
init();
while(scanf("%d", &q), q)
{
num = 0;
memset(book, 0, sizeof(book));
for(i = 0; i < MAXN; i++) s[i].clear();
printf("Case #%d:\n", kase++);
while(q--)
{
scanf(" %c %d", &ch, &x);
if(ch == 'I' && !book[x])
{
book[x] = 1; num++;
for(i = 1; i * i < x; i++)
{
if(x % i) continue;
add(i, cnt[x / i]);
add(x / i, cnt[i]);
}
if(i * i == x) add(i, cnt[i]);
}
if(ch == 'D' && book[x])
{
book[x] = 0; num--;
for(i = 1; i * i < x; i++)
{
if(x % i) continue;
del(i, cnt[x / i]);
del(x / i, cnt[i]);
}
if(i * i == x) del(i, cnt[i]);
}
if(ch == 'Q')
{
if(num == 0)
{
printf("-1\n"); continue;
}
ans = inf;
for(i = 1; i * i <= x; i++)
{
if(x % i) continue;
ans = min(ans, query(x / i) + cnt[i]);
ans = min(ans, query(i) + cnt[x / i]);
}
printf("%d\n", ans == inf ? -1 : ans);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: