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\n");
68         else
69             printf("%d\n",vis[k]);
70         return ;
71     }
72     ll ans=maxV;
73     DFS(0,62,1,1,ans);
74     if(ans >= maxV)
75         printf("INF\n");
76     else
77         printf("%lld\n",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 }

原文地址:https://www.cnblogs.com/violet-acmer/p/10753433.html

时间: 2024-11-04 13:19:13

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

HDU4542 小明系列故事——未知剩余系

题意:给一系列操作,每个操作有两个数t和k,t=0表示求k以内的最大反素数:t=1表示求小于k且与k互质的数的个数. 分析:对第一个操作,直接用dfs求反素数就行了,直接上反素数的模板:第二个操作素数筛法的思想预先打个表. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<algorithm> #include<cstring>

hdu 4506 小明系列故事——师兄帮帮忙

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4506 题目大意:找规律,判断k的t次幂前面的系数. 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 __int64 fun(__int64 a,__int64 b) 6 { 7 __int64 s=1; 8 while (b) 9 { 10 if (b%2==1) 11 s=s*a%1000000

hdu 4511 小明系列故事——女友的考验

小明系列故事——女友的考验 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 822    Accepted Submission(s): 176 Problem Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则

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

小明系列故事--女友的考验 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1734    Accepted Submission(s): 466 Problem Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规

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

Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则: 1.假设小明在的位置是1号点,女朋友在的位置是n号点,则他们之间有n-2个点可以走,小明每次走的时候只能走到比当前所在点编号大的位置: 2.小明来的时候不能按一定的顺序经过某些地方.比如,如果女朋友告诉小明不能经过1 -> 2 -> 3,那么就要求小明来的时候走过的路径不能包含有1 -> 2 ->

AC自动机 + 二维最短路 HDU 4511 小明系列故事――女友的考验

这个题还是比较好想的. 首先将所有不可行方案建立AC自动机,然后跑最短路. 首先将小明放在(sta = 0,pos = 0)处,sta表示AC自动机上点的编号,pos表示坐标点的编号. 根据pos枚举下一次可以到达的地方[pos+1,n],然后sta在自动机上移动,如果某一步会使sta位于有标记的节点,那么这一步是不可行. #include <iostream> #include<time.h> #include<stdio.h> #include<string.

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

广搜. 根据题意,可以知道状态总共有$4*n*m$种.每一个位置四种状态:两个都没有发现:发现$E$没发现$D$:发现$D$没发现$E$:两个都发现. 每次移动的花费都是$1$,队列里面状态的费用是单调不减的,所以第一次符合要求的位置就是答案. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath&g

hdu 4528 小明系列故事——捉迷藏

一开始很疑惑自己为什么错了,后来才知道原来这题是可以往回 走的.开4维visit数组记录状态,状态不同则往回走,相同再往回走. 1 30 31 95 S.............................. ..X............................ ...X........................... ....X.......................... .....X......................... ......X........

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

题意:从 1 走到 n,要求所走路径不能出现给定的路径,求最短路 思路:因为要求不能出现给定路径,那么我可以求助ac自动机完成判断. 我们可以在build的时候标记哪些路径不能出现,显然下面这种表示后缀不能出现,那么他也不能出现 if(node[node[u].fail].cnt && u) node[u].cnt = 1; //都不能取 然后再把图建完整.因为如果一个路径不在Trie中有两种情况,一种是他可能是某个不能走的串的前缀,那么我就重新指向这个不能走的串,比如Trie中只有AT,