[关闭]
@xiaoziyao 2021-03-22T05:41:50.000000Z 字数 3516 阅读 876

P4930 [PA2013]Euler解题报告

解题报告


P4930 [PA2013]Euler解题报告:

更好的阅读体验

题意

组数据,给定,求的所有。(

分析

原来的题目数据有锅,修完数据后拿到了首杀。

搜索题。

首先求出的所有因子计入,然后把所有中为质数的值存入,不难发现很小,也很小,随便交几发讨论一下就可以知道最大是最大是

为数字质因数中的排名,但由于这里可能存不下,因此考虑对于的大小讨论:如果则将的排名存入,否则将的排名存入,这样就只需要开的数组了。

然后就开始玄学起来了。

代表中第一个是因子的数的编号,(如果不存在则为

这里介绍一个众所周知的结论:对于,满足(下面有证明)。

然后进行搜索:表示现在搜索到第了,将除到了(这个为值),并把答案乘到了,边界就是的时候直接把放入答案。

不难发现一定在里(可以通过找到),因此我们可以通过跳过那些不能整除

然后再分类讨论就好了:

复杂度很玄学,但跑的很稳。

代码

记得特判,还有有些地方需要排序。

  1. #include<stdio.h>
  2. #include<algorithm>
  3. #define int long long
  4. using namespace std;
  5. const int maxn=1000005,maxm=2505,maxk=700;
  6. int T,n,cnt,m,Ps,Ds,anss;
  7. int p[maxn],a[maxn],P[maxk],D[maxm],ans[maxn],ord[maxn],nord[maxn],f[maxm][maxk];
  8. void sieve(int n){
  9. for(int i=2;i<=n;i++){
  10. if(p[i]==0)
  11. a[++cnt]=i;
  12. for(int j=1;j<=cnt;j++){
  13. if(i*a[j]>n)
  14. break;
  15. p[i*a[j]]=1;
  16. if(i%a[j]==0)
  17. break;
  18. }
  19. }
  20. }
  21. int check(int x){
  22. if(x<=1000000)
  23. return p[x]==0;
  24. for(int i=2;i*i<=x;i++)
  25. if(x%i==0)
  26. return 0;
  27. return 1;
  28. }
  29. void dfs(int pos,int val,int now){
  30. if(now==1){
  31. ans[++anss]=val;
  32. return ;
  33. }
  34. if(now<=m)
  35. pos=f[ord[now]][pos];
  36. else pos=f[nord[n/now]][pos];
  37. if(pos==Ps+1)
  38. return ;
  39. dfs(pos+1,val,now);
  40. val*=P[pos],now/=P[pos]-1,dfs(pos+1,val,now);
  41. while(now%P[pos]==0)
  42. val*=P[pos],now/=P[pos],dfs(pos+1,val,now);
  43. }
  44. signed main(){
  45. scanf("%lld",&T),sieve(1000000);
  46. while(T--){
  47. scanf("%lld",&n);
  48. if(n==1){
  49. puts("2\n1 2");
  50. continue;
  51. }
  52. for(m=1;1ll*(m+1)*(m+1)<=n;m++);
  53. for(int i=1;i<=m;i++)
  54. if(n%i==0){
  55. D[++Ds]=i;
  56. if(check(i+1))
  57. P[++Ps]=i+1;
  58. if(1ll*i*i!=n){
  59. D[++Ds]=n/i;
  60. if(check(n/i+1))
  61. P[++Ps]=n/i+1;
  62. }
  63. }
  64. sort(P+1,P+1+Ps),sort(D+1,D+1+Ds);
  65. for(int i=1;i<=Ds;i++){
  66. if(D[i]<=m)
  67. ord[D[i]]=i;
  68. else nord[n/D[i]]=i;
  69. f[i][Ps+1]=Ps+1;
  70. for(int j=Ps;j>=0;j--)
  71. f[i][j]=D[i]%(P[j]-1)==0? j:f[i][j+1];
  72. }
  73. dfs(1,1,n),sort(ans+1,ans+1+anss);
  74. printf("%lld\n",anss);
  75. for(int i=1;i<=anss;i++)
  76. printf("%lld%c",ans[i],i==anss? '\n':' ');
  77. if(anss==0)
  78. puts("");
  79. for(int i=1;i<=Ds;i++){
  80. if(D[i]<=m)
  81. ord[D[i]]=0;
  82. else nord[n/D[i]]=0;
  83. }
  84. anss=Ds=Ps=0;
  85. }
  86. return 0;
  87. }

证明

这里有一份时代久远的关于上面式子的证明:

引理:欧拉函数的积性
构造一个)的矩阵:


易知每一行都是m的完全剩余系,那么对于所有,都有
因此有
也很容易证明每一列都是的完全剩余系。
反证法:设同余,且,那么
也就是
两式相减得
又因为,所以那么不难发现,所以每一列都是的完全剩余系。
由欧拉函数的定义得矩阵内可以找到列,其中有个元素同时与m和n互素,即共个元素与互素,也就是与互素。

然后证明欧拉函数的公式:对于,满足

首先很显然为质数的时候,

然后是时(为质数,):

很容易证明等价,那么可以发现与不互素的数只有个数。

那么

为任意正整数时,设,由的积性可知

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注