逆欧拉函数(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 |