[关闭]
@lychee123 2017-09-06T15:16:45.000000Z 字数 2767 阅读 1023

小知识点

数论


求小于等于N的与N互质的数的和:ans=N*phi(N)/2

最大公约数公式:
  1. int gcd(int a,int b)
  2. {
  3. if(b==0)
  4. return a;
  5. return gcd(b,a%b);
  6. }
  7. 我们可以知道的
  8. 1.gcd(0,b)=b;
  9. 2.gcd(a,b)=gcd(b,a%b);
最小公倍数:
  1. int lcm=a/gcd(a,b)*b;(防止爆longlong)

给了两个互质的数A,B。
A*x+B*y(x>=0,y>=0)
问最大不能表示的数,和不能表示的数的个数。

数论知识;
个数就是(A-1)*(B-1)/2;
最大不能表示的数就是 A*B-A-B;

要求解的是N阶乘的结果有多少个0?(1<=N<=1000000000)
注意一下几个方面:
1、任何一个自然数都可分解质因数。N!=1*2*3*(2*2)*5*(2*3)*...*N=2^a*3^b*5^c*7^d......=(2*5)^c*2^(a-c)*3^b*7^d......=10^c*2^(a-c)*3^b*7^d......
2、两数相乘产生0,是因为2和5相乘。又由于在分解质因数时小的质数的幂次一定>=大的质数的幂次,在N!中2的个数显然大于5的个数,故解决该题转化成找出N!中5的幂次。
3、如何找出5的幂次呢?其实就是 N!中:是5的倍数的数+是5^2的倍数的数+5^3的倍数的数+.....
如50!中: 
含有10个5的倍数的数:5,15,20,25,30,35,40,45,50 [50/5=10] 
含有2个5^2的倍数的数:25,50 [50/(5^2)=2] 
可见N!中一共有12个5相乘,那么N!结果中的0也必有12个。

如何求素数

  1. void pri()
  2. {
  3. int num=0,i,j,k;
  4. for(i=1;i<=20000;i++)
  5. {
  6. k=(int)sqrt(i);
  7. for(j=2;j<=k;j++)
  8. if(i%j==0)
  9. break;
  10. if(j>k)
  11. a[num++]=i;
  12. }
  13. /*for(i=0;i<num;i++)
  14. printf("%d ",a[i]);*/
  15. }

素数筛选模板

  1. On
  2. #define MAXN 1000010
  3. int ans[MAXN];
  4. bool vis[MAXN];;
  5. void pri()//素数筛选
  6. {
  7. int t=0;
  8. memset(vis,true,sizeof(vis));
  9. for(int i=2;i<=MAXN;i++)
  10. {
  11. if(vis[i]==1)
  12. {
  13. t++;
  14. ans[t]=i;
  15. }
  16. for(int j=1;((j<=t)&&(i*ans[j]<=MAXN));j++)
  17. {
  18. vis[i*ans[j]]=false;
  19. if(i%ans[j]==0)
  20. break;
  21. }
  22. }
  23. }
  24. O(nlog(n)):
  25. const int maxn=100000+10;
  26. bool v[maxn];
  27. int ans[maxn];
  28. void getPrime(int n,int &tot)
  29. {
  30. tot=0;
  31. for(int i=2;i<=n;i++)
  32. v[i]=true;
  33. for(int i=2;i<n;i++)
  34. if(v[i])
  35. {
  36. if(n/i<i) break;
  37. for(int j=i*i;j<=n;j+=i)
  38. v[j]=false;
  39. }
  40. for(int i=2;i<=n;++i)
  41. if(v[i])ans[++tot]=i;
  42. }

欧拉函数

  1. //phi(n)为不超过n且与n互质的正整数个数
  2. int phi(int n)
  3. {
  4. int m=(int)sqrt(n+0.5);
  5. int ans=n;
  6. for(int i=2;i<=m;i++)
  7. if(n%i==0)
  8. {
  9. ans=ans/i*(i-1);
  10. while(n%i==0)
  11. n/=i;
  12. }
  13. if(n>1)
  14. ans=ans/n*(n-1);
  15. return ans;
  16. }

扩展欧几里得

求方程 ax + by = gcd(a,b)的一组解,这组解x为最小的正整数。
通解为 ,

  1. void exgcd(int a, int b, int &x, int &y)
  2. {
  3. if (b == 0)
  4. {
  5. x = 1;
  6. y = 0;
  7. return;
  8. }
  9. exgcd(b, a%b, x, y);
  10. int t = x;
  11. x = y;
  12. y = t - (a / b)*y;
  13. }

费马小定理

p是素数 gcd(a,p)=1;
a^(p-1) %p = 1

欧拉定理

gcd(a,p)=1;


同余式:a=b(%m)表示a%m=b%m或者a+km=b;
同余方程:ax=b(%m),求解x相当于解ax+my=b;

中国剩余定理

求模线性方程组的最小正整数解。

  1. #include<bits/stdc++.h>
  2. typedef long long LL;
  3. using namespace std;
  4. LL exgcd(LL a, LL b, LL &x, LL &y)
  5. {
  6. if (b == 0)
  7. {
  8. x = 1;
  9. y = 0;
  10. return a;
  11. }
  12. LL ret = exgcd(b, a % b, x, y);
  13. LL t = x;
  14. x = y;
  15. y = t - (a / b) * y;
  16. return ret;
  17. }
  18. LL lcm(LL a, LL b)
  19. {
  20. return a / __gcd(a, b) * b;
  21. }
  22. LL CRT(LL m[], LL a[], int n)
  23. {
  24. LL X = a[1];
  25. LL LCM = m[1];
  26. for (int i = 2; i <= n; i++)
  27. {
  28. LL x, y;
  29. a[i] -= X;
  30. a[i] = (a[i] % m[i] + m[i]) % m[i];
  31. int d = exgcd(LCM, m[i], x, y);
  32. if (a[i] % d) return -1;
  33. x *= a[i] / d;
  34. x = (x % (m[i] / d) + m[i] / d) % (m[i] / d);
  35. X += LCM * x;
  36. LCM = lcm(LCM, m[i]);
  37. }
  38. return X;
  39. }

求小于某个数n的素数的个数

  1. #include <bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. ll f[340000], g[340000], n;
  5. void init()
  6. {
  7. ll i, j, m;
  8. for(m = 1; m * m <= n; ++m)f[m] = n / m - 1;
  9. for(i = 1; i <= m; ++i)g[i] = i - 1;
  10. for(i = 2; i <= m; ++i)
  11. {
  12. if(g[i] == g[i - 1])continue;
  13. for(j = 1; j <= min(m - 1, n / i / i); ++j)
  14. {
  15. if(i * j < m)f[j] -= f[i * j] - g[i - 1];
  16. else f[j] -= g[n / i / j] - g[i - 1];
  17. }
  18. for(j = m; j >= i * i; --j)g[j] -= g[j / i] - g[i - 1];
  19. }
  20. }
  21. int main()
  22. {
  23. while(scanf("%lld", &n) != EOF)
  24. {
  25. init();
  26. cout << f[1] << endl;
  27. }
  28. return 0;
  29. }

线性预处理逆元

注意inv的数据类型为long long,否则会爆int

for (int i = 2; i < MAXN; i++) inv[i]  = (MOD - MOD / i) * inv[MOD % i] % MOD;
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注