济南学习 Day 5 T2 pm

逆欧拉函数(arc)
题目描述:
已知phi(N),求N。
输入说明:
两个正整数,分别表示phi(N)和K。
输出说明:
按升序输出满足条件的最小的K个N。
样例输入:
8 4
杨丽输出:
15 16 20 24
数据范围:
对于20%的数据 phi(N)<=100
对于40%的数据 phi(N)<=10^5
对于80%的数据 phi(N)<=10^9
对于100%的数据 phi(N)<=10^14,K<=1000
其中有60%的数据满足K=1
输入数据保证符合题意,且满足答案中最大的数不超过10^14。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<ctime>
 6 #define ll long long 
 7 using namespace std;
 8 const ll N=1e7;
 9 const ll M=1e5+10;
10 ll n,k,tot,prime[N/10],ans[M];
11 bool check[N+10];
12 void prepare()
13 {
14     ll x=min(N,n*100);
15     for(ll i=2,t;i<=x;i++)
16     {
17         if(!check[i]) prime[++tot]=i;
18         for(ll j=1;j<=tot&&(t=prime[j]*i)<=x;j++)
19         {
20             check[t]=1;
21             if(i%prime[j]==0) break;
22         }
23     }
24 }
25 ll mul(ll x,ll y,ll z)
26 {
27     ll r=0;
28     for(;y;x<<=1,x%=z,y>>=1)
29     {
30         if(y&1)
31           r+=x,r%=z,y--;
32     }
33 }
34 ll Qc(ll x,ll y,ll z)
35 {
36     ll r=0;
37     for(;y;x<<=1,x%=z,y>>=1)
38       if(y&1)
39         r=mul(r,x,z);
40     return r;
41 }
42 bool is_prime(ll n)
43 {
44     if(n<2) return 0;
45     if(n==2) return 1;
46     if(!(n&1)) return 0;
47     ll m=n-1,j=0;
48     for(;!(m%1);j++,m>>=1);
49     for(ll a,x,y,i=1;i<=5;i++)
50     {
51         a=rand()%(n-1)+1;
52         x=Qc(a,m,n);
53         for(ll k=1;k<=j;k++){
54             y=mul(x,x,n);
55             if(y==1&&x!=1&&x!=n-1) return 0;
56             x=y;
57         }
58         if(x!=1) return 0;
59     } 
60     return 1;
61 }
62 void dfs(ll x,ll y,ll z)
63 {
64     if(x==1)
65     {
66         ans[++ans[0]]=y;return;
67     }
68     if(z<=0) return;
69     if(x+1>prime[tot]&&is_prime(x+1)) ans[++ans[0]]=y*(x+1);
70     for(ll a,b,c,i=z;i;i--)
71     {
72         if(x%(prime[i]-1)==0)
73         {
74             a=x/(prime[i]-1);b=y;c=1;
75             while(a%c==0)
76             {
77                 b*=prime[i];
78                 dfs(a/c,b,i-1);
79                 c*=prime[i];
80             }
81         }
82     } 
83 }
84 int main()
85 {
86     srand(time(0));
87     scanf("%I64d%I64d",&n,&k);
88     prepare();
89     dfs(n,1,tot);
90     sort(ans+1,ans+ans[0]+1);
91     for(int i=1;i<=k;i++)
92       printf("I64d ",ans[i]);
93     return 0;
94 }

思路:

算法一

暴力枚举N,暴力求出phi(N)验证答案。

 

时间复杂度:O(N^1.5)或O(N^2logN)或O(N^(5/4)logN)

期望得分:20-50

算法二

在算法一的基础上,求phi用欧拉线性筛法。

 

时间复杂度:O(N)

期望得分:50

算法三

考虑到原数只可能有一个大于10^7的质因子。考虑将phi(N)分解,在10^7范围内从大到小暴力搜索质因子试除(从大到小搜索可使状态树上紧下宽),并记录对应的N。一个明显的优化就是如果当前数加一为大于10^7的一个质数(用Miller-Rabin素性测试判)就可以停止这一状态的继续搜索了。虽然看起来复杂度很吓人,不过由于满足条件的N较少等等种种原因,实测还是相当快的。

 

时间复杂度:O(?)

期望得分:100

原文地址:https://www.cnblogs.com/suishiguang/p/6041471.html