hdu 4542 "小明系列故事——未知剩余系" (反素数+DFS剪枝)

Posted violet-acmer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4542 "小明系列故事——未知剩余系" (反素数+DFS剪枝)相关的知识,希望对你有一定的参考价值。

 

传送门

 

参考资料:

  [1]:https://blog.csdn.net/acdreamers/article/details/25049767

 

题意:

  输入两个数 type , k;

  ①type = 0,求[1,262]中的因子个数为 k 的反素数,如果求解的答案 > 262,输出"INF";

  ②type = 1,求使得 num-factor[num] = k 的最小的num;

题解:

  只有当 type = 1 时,才有可能输出 "Illegal";

  那,什么情况下才会输出呢?

  考虑一点,当 num 很大时,num-factor[num]也会随之变大,因为 k 最大为 47777,所以,对于type=1的情况,可以预处理出来;

技术图片
 1 int vis[maxn];//vis[i]:保存的是num-factor[num]=i的最小的num
 2 void factorTable()//因子表
 3 {
 4     fill(factor,factor+maxn,1);
 5     for(int i=2;i < maxn;++i)
 6     {
 7         if(factor[i] != 1)
 8             continue;
 9         for(int j=i;j < maxn;j+=i)
10         {
11             int k=0;
12             for(int m=j;m%i == 0;m/=i,k++);
13             factor[j] *= k+1;
14         }
15     }
16     mem(vis,INF);//初始为INF
17     for(int i=1;i < maxn;++i)
18         vis[i-factor[i]]=min(vis[i-factor[i]],i);
19 }
预处理出1e5前的因子表

  那么,当 type = 0 时,就和之前的题一个做法了,不过,需要剪枝才能过;

AC代码:

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 #define INFull ~0ULL
 5 #define ll long long
 6 #define ull unsigned long long
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 const int maxn=1e5+50;
 9 const ll maxV=(1ll*1<<62)+1;
10 
11 int k,type;
12 int factor[maxn];
13 int vis[maxn];//vis[i]:保存的是num-factor[num]=i的最小的num
14 int prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
15 
16 void factorTable()//因子表
17 {
18     fill(factor,factor+maxn,1);
19     for(int i=2;i < maxn;++i)
20     {
21         if(factor[i] != 1)
22             continue;
23         for(int j=i;j < maxn;j+=i)
24         {
25             int k=0;
26             for(int m=j;m%i == 0;m/=i,k++);
27             factor[j] *= k+1;
28         }
29     }
30     mem(vis,INF);//初始为INF
31     for(int i=1;i < maxn;++i)
32         vis[i-factor[i]]=min(vis[i-factor[i]],i);
33 }
34 /**
35     根据反素数的性质可知:
36     当前素数的指数要小于等于之前比起小的素数的指数
37     这就是limit的作用,剪枝1
38     初始为62(最大为2的62次幂)
39 */
40 void DFS(int dep,int limit,ll curNum,int curK,ll &ans)
41 {
42     if(curK == k && curNum < ans)
43         ans=curNum;
44 
45     for(int i=1;i <= limit;++i)
46     {
47         //向后遍历,i会增大,如果当前的 curK*(i+1) > k,那么之后的肯定也大于k
48         if(ans/curNum < prime[dep] || curK*(i+1) > k)//剪枝2
49             break;
50 
51         curNum *= prime[dep];
52         /**
53             如果curK*(i+1) = k,那么,势必组成curK的所有的(i+1)都为k的因子
54             例如:
55             假设k=(p1+1)*(p2+1)*......*(pn+1)
56             那么k%(p1+1)=0,k%(p2+1)=0,....,k%(pn+1)=0;
57         */
58         if(k%(curK*(i+1)) == 0)//剪枝3
59             DFS(dep+1,i,curNum,curK*(i+1),ans);
60     }
61 }
62 void Solve()
63 {
64     if(type)//type = 1
65     {
66         if(vis[k] == INF)//判断是否有解
67             printf("Illegal
");
68         else
69             printf("%d
",vis[k]);
70         return ;
71     }
72     ll ans=maxV;
73     DFS(0,62,1,1,ans);
74     if(ans >= maxV)
75         printf("INF
");
76     else
77         printf("%lld
",ans);
78 }
79 int main()
80 {
81 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
82     factorTable();
83     int test;
84     while(~scanf("%d",&test))
85     {
86         for(int i=1;i <= test;++i)
87         {
88             scanf("%d%d",&type,&k);
89             printf("Case %d: ",i);
90             Solve();
91         }
92     }
93     return 0;
94 }
View Code

 

以上是关于hdu 4542 "小明系列故事——未知剩余系" (反素数+DFS剪枝)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4528 小明系列故事――捉迷藏

HDU 4511小明系列故事——女友的考验(AC自动机+DP)

HDU 4511 小明系列故事——女友的考验 (AC自动机 + DP)题解

HDU 4511 小明系列故事——女友的考验 ( Trie图 && DP )

hduoj 4506 小明系列故事――师兄帮帮忙分析题意

HDU 4521 小明系列问题——小明序列 (线段树维护DP)