约数和欧拉函数
约数个数问题:
1.1-n中的约数个数:
1.怎么求个数:分解质因子后
(c1+1)(c2+1)...
2.估算复杂度:1-n当中有每个数中的约数个数和
N/1+N/2+.. 总共是nlogn个
3.0-2e9 最多的约数个数是1600个数
T2
- 数论题目本身就需要对式子进行一定的推导
- 对于二元问题,我们转化成y=f(x)的形式
- 进而问题变成:对于多少个x,有等式成立并y满足题目条件(正,整数)
- 根据枚举的思路,分子分母中只出现一个x才好枚举
- 如果最后缺乏条件,不妨回到原本的式子当中寻找
- 最后得出是求n!^2的约束
求n!的约数个数:
- 对于求这个,转化思想,变成每一个质数对于他的倍数有多大的贡献(乘法容易取模难)
- 每次从n开始,寻找一共有多少个数是含有k个p的
- 核心代码:for(int j=n;j;j/=p) s+=j/p;
T3
转化思路:约数个数最多的最小的数
- 1.不同的质因子的个数数很小的<9
- 2.每个质因子的次数小于30
- 3.所有质因子的次数是递减的:小的先填
- 数论优先思想【可以手算来先确定一下数据范围】
- 2147483647(2^32-1)
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; #define ll long long int prime[9]={2,3,5,7,11,13,17,19,23}; int n; int maxd,num; inline void dfs(int j,int ci,int p,int yue) { if(yue>maxd||(yue==maxd&&p<num)) { num=p; maxd=yue; } if(j==9) return;// for(int i=1;i<=ci;i++) { if((ll)p*prime[j]>n) break;//此处考虑爆int 开ll p*=prime[j]; dfs(j+1,i,p,yue*(i+1)); } return; } int main() { scanf("%d",&n); dfs(0,30,1,1);//从1开始 printf("%d",num); return 0; }
注意一下爆搜的写法:
- 1.明确搜索顺序(质数从小到大)->搜索边界(u==9)
- 明确含参数:上一个的次数,当前枚举的个数,当前的乘积(防止爆炸)(prime*p>n),当前约数个数
- 更新答案:(yue>maxd||yue==maxd&&p<num)
- 更新过程:枚举次数 1->ci就
T4hanson的趣味题
- (a,x)=b [c,x]=d求1-n当中有多少的n是满足的
- 分析题目,二元条件转验证,枚举x需要找范围
- 发现x是d的约数,所以转为找d的约数
- 发现枚举需要根号n;
- 根据思想:质因子的个数是很少的(x/lnx)所以考虑分解质因子,优化10倍
-
View Code#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn=50000; typedef long long ll; int prime[maxn],cnt; bool st[maxn]; struct Factor { int p,s; }f[maxn]; int fcnt; int dive[maxn],dcnt; inline void init(int n) { for(int i=2;i<=n;i++) { if(!st[i]) prime[cnt++]=i; for(int j=0;i*prime[j]<=n;j++) { st[i*prime[j]]=true; if(i%prime[j]==0) break; } } } inline int gcd(int a,int b) { if(b==0 )return a; else return gcd(b,a%b); } inline void dfs(int u,int p) { if(u==fcnt) { dive[dcnt++]=p; return; } for(int i=0;i<=f[u].s;i++) { dfs(u+1,p); p*=f[u].p; } } int main() { init(maxn); int n; scanf("%d",&n); while(n--) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); int t=d; fcnt=0; for(int i=0;prime[i]<=t/prime[i];i++) { int p=prime[i]; if(t%p==0) { int s=0; while(t%p==0) t/=p,s++; f[fcnt++]={p,s}; } } if(t>1) f[fcnt++]={t,1}; dcnt=0; dfs(0,1); int res=0; for(int i=0;i<dcnt;i++) { int x=dive[i]; if(gcd(a,x)==b&&(ll)c*x/gcd(c,x)==d) res++; } printf("%d\n",res); } return 0; }
- 核心思想:枚举出每一个质因子来计算贡献,在int类型里面约数数量最大也就是1600
- 注意指数枚举范围是0-s
二.欧拉函数:
T1可见的点
- 分析题意:发现是摆在二维坐标系上的点
- 换种说法,也就是每个直线y=kx上面的第一个整数对的点
- 问题转化为求多少个实数对满足
- 根据"找性质“原则,第一个的满足要求也就是 (x0,y0)互质【否则就可以写成n*x0,n*y0的形式】
- 由此转化成求1-n有多少个互质的数
- 发现和欧拉函数性质很像,考虑向其靠拢
- 考虑"对称,特殊,旋转“减少维度的原则,发现只需要求一边
- 问题得解
- 代码如下
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; const int maxn=1010; int prime[maxn],cnt; bool st[maxn]; int phi[maxn]; inline void init(int n) { phi[1]=1; for(int i=2;i<=n;i++) { if(!st[i]) { phi[i]=i-1; prime[cnt++]=i; } for(int j=0;i*prime[j]<=n;j++) { st[prime[j]*i]=true; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j];//(˵Ã÷֮ǰÒѾ±»É¸¹ý£¬²»ÊÇ×îСµÄÖÊÒò×Ó£¬Ö»ÐèÒªÔÙ³ËÉÏÖ¸Êý¾Í¿É break; } phi[prime[j]*i]=phi[i]*(prime[j]-1);//ȡģÓÐÓ࣬˵Ã÷ ÒªÔÙ³ËÉÏpk(1-1/pk)Ò²¾ÍÊÇpk-1 } } } int main() { init(maxn); int n,m; scanf("%d",&m); for(int t=1;t<=m;t++) { scanf("%d",&n); int res=0; for(int j=1;j<=n;j++) res+=2*phi[j]; printf("%d %d %d\n",t,n,res+1); } return 0; }
- 注释补充:
- 若i%prime[j]==0,说明之前已经被筛过,只需要乘p就可
- 否则,p是其中一个质因子,需要乘p(1-1/p)也就是p-1
- 总结经验【二维图形可以映射到坐标系上,然后数行结合,根据对称,旋转的性质向已知靠拢】
T2 最大公约数
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const int maxn=1e7+10; int prime[maxn],cnt; bool st[maxn]; int phi[maxn]; ll s[maxn]; inline void init(int n) { for(int i=2;i<=n;i++) { if(!st[i]) { prime[cnt++]=i; phi[i]=i-1; } for(int j=0;i*prime[j]<=n;j++) { st[i*prime[j]]=true; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(int i=1;i<=n;i++) s[i]=s[i-1]+phi[i]; } int main() { int n; scanf("%d",&n); init(n); ll res=0; for(int i=0;i<cnt;i++) { res+= s[n/prime[i]]*2 + 1; } printf("%lld",res); }
- 判断:注意明显需要开ll
- 分析题意:1e7的数据范围(x,y)=p等价于(x/p,y/p)=1【原则:等价变换】
- 转化为对于每一个p求gcd=1(也就是互质)有多少个
- 【框架细节原则】:检验一下优解需不需要对其进行优化或者补充
- 转化为欧拉函数就可
浙公网安备 33010602011771号