HDU 5812 Distance
题意是,一堆操作,I是添加一个数,D是去掉一个数,Q是询问这个数如果通过乘除质数,x次能到集合中任何一个数,问最少次数。
NUM是每个数的质因子个数,通过筛法筛出来;这里规定乘一个质数称之为一次,Ci,j是指i这个数,j次能到达集合中的数的数量。ans中是一个二进制数,表示这个可以几次到(相应位置是1),当让也可以直接用c数组去遍历,这样不是看着清楚么
#include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> #include <iostream> #include <cstdlib> #include <string> #include <vector> #include <set> using namespace std; const int INF = 0x7f7f7f7f; const int MAXN = 1e6 + 11; int num[MAXN]; int c[MAXN][21]; int ans[MAXN]; void init() { num[1] = 0; for (int i = 2; i < MAXN; ++i) { if (!num[i]) { num[i] = 1; for (int j = i + i; j < MAXN; j += i) { int temp = j; while (temp % i == 0) { ++num[j]; temp /= i; } } } } } set<int>st; set<int>::iterator iter; int main() { init(); int T,p,ncas=1; char s[5]; while (scanf ("%d",&T)&&T) { st.clear(); memset(c,0,sizeof(c)); memset(ans,0,sizeof(ans)); printf ("Case #%d:\n",ncas++); while (T--) { scanf ("%s%d",s,&p); if (s[0]=='I') { if ( (iter = st.find(p)) != st.end() )continue; else st.insert(p); for (int i=1; i*i<=p; i++) { if (p%i==0) { int a=i,b=p/i; c[a][num[b]]++; if (c[a][num[b]]==1) ans[a]+=(1<<num[b]); c[b][num[a]]++; if (c[b][num[a]]==1) ans[b]+=(1<<num[a]); } } } else if (s[0]=='D') { if ( (iter = st.find(p)) == st.end() )continue; else st.erase(p); for (int i=1; i*i<=p; i++) { if (p%i==0) { int a=i,b=p/i; c[a][num[b]]--; if (c[a][num[b]]==0) ans[a]-=(1<<num[b]); c[b][num[a]]--; if (c[b][num[a]]==0) ans[b]-=(1<<num[a]); } } } else { int out=0x7f7f7f7f; if (st.size()) { for (int i=1; i*i<=p; i++) { if (p%i==0) { int j,a=i,b=p/i; for (j=0; j<22; j++) { if (ans[a]&(1<<j)) break; } if (j!=22) out=min(out,j+num[b]); for (j=0; j<22; j++) { if (ans[b]&(1<<j)) break; } if (j!=22) out=min(out,j+num[a]); } } } if (out==0x7f7f7f7f) printf ("-1\n"); else printf ("%d\n",out); } } } return 0; }