• HDU 5812 Distance


    题目:Distance

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5812

    题意:定义d(x,y)是x 变成y 至少需要的操作次数,每一次操作可以乘以或除以一个质数(必须能整除)。现在,有一个集合s,初始为空,每一次有可能插入一个数(如果已经存在就无视),有可能删除一个数(如果没有就无视),有可能给出一个数x,问d(x,y)的最小值,y属于集合s,如果集合为空输出-1。

    思路:

      首先想到最普通的做法,对于每一次询问x,遍历集合中已经存在的数y,令num[i]为i 的质因子数目,那么d(x,y)=num[x/gcd(x,y)]+num[y/gcd(x,y)],就是要加上y 独有的质因子,再减去x 独有的质因子。这里,num数组可以预处理,但每一次询问就要遍历集合中所有元素,时间复杂度高达O(n^2),肯定是要超时的。

      不过,从上面的做法可以得到启发,每一次询问x,我们可以枚举x 的约数g,然后对于集合中的y,d(x,y)=d(x,g)+d(g,y)。很容易想到,约数最多100万个,那么我们用d 数组保存每个约数到集合中的y 的最小变化次数(暂不考虑删除),然后枚举x 的所有约数(最多也就几十个),就可以计算出解,也就是 num[x/g]+d[g]。d 数组的维护就是在插入的时候进行的,比如插入x,枚举x 的所有约数g,d[g]=min(d[g],num[x/g])。当然,这是对付没有删除的情况下,有删除,肯定不能只保存最小的那个了。

      不过,现在问题就很简单了,我们可以弄100万个类型为Node的优先队列,Node包含val(集合中已经存在的数),num(val到这个优先队列表示的约数i 的变化次数)排序方式就是num越小越好,再开一个标记数组u,初始化为0,u[i]=0就表示i 不存在,也就是说q[j]的队头,u[val]如果为0,那么说明val已经被删除,就不能充数,而是出队,继续判断下一个。

    AC代码:

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<string.h>
      4 #include<map>
      5 #include<queue>
      6 using namespace std;
      7 #define N 1000010
      8 #define LL long long
      9 #define INF 2147483647
     10 int num[N]={0};
     11 int prim[N],po=0;
     12 
     13 
     14 int gcd(int a,int b)
     15 {
     16   return b?gcd(b,a%b):a;
     17 }
     18 int min(int x,int y)
     19 {
     20   return x<y?x:y;
     21 }
     22 
     23 int gg[N],go;
     24 pair<int,int> bt[100000];
     25 int bo;
     26 void dfs(int i,int all)
     27 {
     28   if(i==bo)
     29   {
     30     gg[go++]=all;
     31     return ;
     32   }
     33   int k=1;
     34   for(int j=0;j<=bt[i].second;j++)
     35   {
     36     dfs(i+1,all*k);
     37     k=k*bt[i].first;
     38   }
     39 }
     40 
     41 void fun(int x)
     42 {
     43   bo=0;
     44   int i=0;
     45   while(i<po && prim[i]*prim[i]<=x)
     46   {
     47     int flag=0;
     48     bt[bo].second=0;
     49     while(x%prim[i]==0)
     50     {
     51       bt[bo].second++;
     52       flag=1;
     53       x/=prim[i];
     54     }
     55     if(flag==1) bt[bo++].first=prim[i];
     56     i++;
     57   }
     58   if(x!=1)
     59   {
     60     bt[bo].first=x;
     61     bt[bo++].second=1;
     62   }
     63   dfs(0,1);
     64 }
     65 bool u[N];
     66 struct Node
     67 {
     68   int num,val;
     69   bool friend operator < (Node a,Node b)
     70   {
     71     return a.num>b.num;
     72   }
     73 };
     74 
     75 priority_queue<Node> q[N];
     76 int main()
     77 {
     78   num[1]=0;
     79   for(int i=2;i<=N-10;i++)
     80   {
     81     if(!num[i])
     82     {
     83       num[i]=1;
     84       prim[po++]=i;
     85     }
     86     for(int j=0;j<=po && (LL)i*prim[j]<N;j++)
     87     {
     88       num[i*prim[j]]=num[i]+1;
     89     }
     90   }
     91   int n,cas=1;
     92   while(scanf("%d",&n)!=EOF)
     93   {
     94     if(n==0) break;
     95     char t[10];
     96     int x;
     97     printf("Case #%d:
    ",cas++);
     98     memset(u,0,sizeof(u));
     99     while(n--)
    100     {
    101       scanf("%s%d",t,&x);
    102       if(t[0]=='I')
    103       {
    104         if(u[x]==0)
    105         {
    106           go=0;
    107           fun(x);
    108           for(int i=0;i<go;i++)
    109           {
    110             Node tmp;
    111             tmp.num=num[x/gg[i]];
    112             tmp.val=x;
    113             q[ gg[i] ].push(tmp);
    114           }
    115         }
    116         u[x]=1;
    117       }
    118       else if(t[0]=='D')
    119       {
    120         u[x]=0;
    121       }
    122       else
    123       {
    124         go=0;
    125         fun(x);
    126         int mint=INF;
    127         for(int i=0;i<go;i++)
    128         {
    129           int mm=INF;
    130           int m=gg[i];
    131           while(q[m].size())
    132           {
    133             Node tmp=q[m].top();
    134             if(u[tmp.val]==0) q[m].pop();
    135             else
    136             {
    137               mm=tmp.num;
    138               break;
    139             }
    140           }
    141           if(mm==INF) continue;
    142           mint=min(mint,num[x/gg[i]]+mm);
    143         }
    144         if(mint==INF) printf("-1
    ");
    145         else printf("%d
    ",mint);
    146       }
    147     }
    148   }
    149   return 0;
    150 }
  • 相关阅读:
    1069: [SCOI2007]最大土地面积
    Kettle 解决数据锁的问题(事务(进程 ID 51)与另一个进程被死锁在 锁 资源上)
    Kettle配合Windows执行计划实现定时实行作业
    把本地项目同步到码云
    IDEA通过Maven WebApp archetype 创建Spring boot项目骨架
    从零开始完整搭建 Spring-Boot 项目开发框架的教程
    使用IDEA搭建Spring Boot入门项目
    Win10激活失败并提示错误代码0xC004C003的解决方法
    javascript (JS组成、书写位置、基本概念、作用域、内存问题、变量)
    HTML基础之标签
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5757949.html
Copyright © 2020-2023  润新知