数学瞎整理

 

一.质数

 1.筛质数:有两种 一个线性筛,一个欧拉筛。一般用欧拉筛就行了,如果是求一个[l,r] l r大但差的绝对值小的区间,先用线性筛筛前面,然后用欧拉筛筛后面

  欧拉筛O(N log log N)注意每次i循环从2开始 j从i开始 

 1 bool v[N];
 2 int n;
 3 void prime(int n)
 4 {
 5     memset(v,0,sizeof(v));
 6     for(int i=2;i<=n;i++)
 7     {
 8         if(v[i]) continue;
 9         cout<<i<<" ";
10         for(int j=1;j<=n/i;j++) v[i*j]=1;
11     }
12 }

  线性筛 O(N):j从1开始

 1 void primes(int n)
 2 {
 3     memset(v,0,sizeof(v));
 4     cnt=0;
 5     for(int i=2;i<=n;i++)
 6     {
 7         if(!v[i]) prime[++cnt]=i,v[i]=i;
 8         for(int j=1;j<=cnt;j++)
 9         {
10             if(prime[j]>v[i]||prime[j]>n/i) break;
11             v[i*prime[j]]=prime[j];
12         }
13     }
14     for(int i=1;i<=cnt;i++)
15         cout<<prime[i]<<" ";
16 }

 2.质因数分解:试除法。 结合欧拉筛,扫描2~ √N的每个数d, 若d整除N,从N中除掉所有因子d,同时累计除去的d的个数。

 1 void divide(int n)
 2 {
 3     cnt=0;
 4     for(int i=2;i*i<=n;i++)
 5     {
 6         if(n%i==0) 
 7         {
 8             prime[++cnt]=i; c[cnt]=0;
 9             while(n%i==0) n/=i,c[cnt]++;
10         }
11     }
12     if(n>1) prime[++cnt]=n,c[cnt]=1;
13     for(int i=1;i<=cnt;i++)
14         cout<<prime[i]<<"^"<<c[i]<<endl;
15 }

 3.example

 1 #include<bits/stdc++.h>
 2 #define ll long long 
 3 #define N 10000010
 4 #define mod 998244353
 5 using namespace std;
 6 ll prime[N],cnt,v[N];
 7 ll L,R,ans,ans2;
 8 void pre()
 9 {
10     for(int i=2;i<1000000;i++)
11     {
12         if(v[i]==0) v[i]=i,prime[++cnt]=i;
13         for(int j=1;j<=cnt;j++)
14         {
15             if(prime[j]>v[i]||prime[j]>1000000/i) break;
16             v[i*prime[j]]=prime[j];
17         }
18     }
19 }
20 int main()
21 {
22     pre();
23     scanf("%lld%lld",&L,&R);
24     memset(v,0,sizeof(v));
25     for(ll i=1;i<=cnt;i++)
26     {
27         ll st=max(1ll,(L-1)/prime[i])*prime[i]+prime[i];
28         for(ll j=st;j<=R;j+=prime[i])
29         {
30             if(v[j-L]) continue;
31             v[j-L]=1;
32             ans++;
33             ans2=(ans2+prime[i])%mod;
34         }   
35     }
36     printf("%lld %lld",ans,ans2);
37     return 0;
38 }

 二.约数

  • 求约数(集合)

   1.试除法:略

    有一推论:一个整数N的约数个数上界为2√N

   2.倍数法

    推论:1~N每个数的约数个数的总和约为 N log N

 1 vector<int> f[N];
 2 int n;
 3 void pu(int n)
 4 {
 5     for(int i=1;i<=n;i++)
 6         for(int j=1;j<=n/i;j++)
 7             f[i*j].push_back(i);
 8     for(int i=1;i<=n;i++){
 9         for(int j=0;j<f[i].size();j++)
10             cout<<f[i][j]<<" ";
11         cout<<endl;
12     }
13 }

    3.example 反素数

    见P134

 1 #include<bits/stdc++.h>
 2 #define N 2000000000
 3 #define ll long long
 4 using namespace std;
 5 ll n;
 6 ll ans;
 7 int num=1;
 8 int a[11]={0,2,3,5,7,11,13,17,19,23,29};
 9 void dfs(int dep,int dex,ll anss,int cnt)
10 {
11     if(dep==10)
12     {
13         if((anss>ans&&cnt>num)||(anss<=ans&&cnt>=num))
14         {
15             ans=anss; 
16             num=cnt;
17         }
18         return;
19     }
20     int t=1;
21     for(int i=0;i<=dex;i++)
22     {
23         dfs(dep+1,i,anss*t,cnt*(i+1));
24         t*=a[dep];
25         if(anss*t>n) break;
26     }
27 }
28 int main()
29 {
30     scanf("%lld",&n);
31     dfs(1,30,1,1);
32     printf("%lld\n",ans);
33     return 0;
34 }
  • gcd

   1.定理:

  • gcd(a,b)*lcm(a,b)=a*b

  • gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)  (a>=b)

  • gcd(a,b)=gcd(b,a mod b) (b!=0)

   2.一行gcd:

1 int gcd(int a,int b)
2 {
3     return b?gcd(b,a%b):a;
4 }

    3.example hankson

    贼毒了...我是用暴力写的....还用了自带函数__gcd()

 1 #include<bits/stdc++.h>
 2 #define N 20000100
 3 #define ll long long
 4 using namespace std;
 5 ll f[N];
 6 int cnt;
 7 ll a0,a1,b0,b1;
 8 int i;
 9 void div(int x)
10 {
11     cnt=0;
12     for(i=1;i*i<=x;i++)
13         if(x%i==0)
14         {
15             f[++cnt]=i;
16             if(i!=x/i) f[++cnt]=x/i;
17         }
18 }
19 ll ans;
20 void red(ll &x)
21 {
22     ll f=1;x=0;char c=getchar();
23     while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
24     while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
25     x*=f;
26 }
27 void print(ll x)
28 {
29     if(x<0) putchar('-'),x=-x;
30     if(x>9) print(x/10);
31     putchar(x%10+'0');
32 }
33 int main()
34 {
35     ll t;
36     red(t);
37     while(t--)
38     {
39         red(a0);red(a1);red(b0);red(b1);
40         div(b1);
41         ans=0;
42         for(i=1;i<=cnt;i++)
43         {
44             ll yy=__gcd(f[i],b0);
45             if(b0*f[i]/yy!=b1) continue;
46             if(__gcd(f[i],a0)==a1) ans++;
47         }
48         printf("%lld\n",ans);
49     }
50     return 0;
51 }

 三.互质和phi

 1.phi(i)指1~i之间与i互质的数个数

 2.

                

 代码如下:

 1 int phi(int n)
 2 {
 3     int ans=n;
 4     for(int i=2;i*i<=n;i++)
 5         if(n%i==0)
 6         {
 7             ans=ans/i*(i-1);
 8             while(n%i==0) n/=i;
 9         }
10     if(n>1) ans=ans/n*(n-1);
11     return ans;
12 }

 3.性质  (p均为质数)

  • 任意n>1,1~n中与n互质的数的和为 n * phi(n) / 2 ;
  • 若a,b互质,phi(a*b)=phi(a)*phi(b);
  • 若p|n 且 p^2|n, 则phi(n)=phi(n/p)*p;
  • 若p|n 但不满足 p^2|n,则phi(n/p) * (p-1);
  • d|n phi(n)=n;

 

四.同余

  • PRE

   1.费马小定理:

      

  证明在这里

   2.欧拉定理:若正整数a,n 互质

      

   3. 欧拉定理的推论:

   (mod n)

   由此,我们在计算乘方算式需要取模时,可以先把底数对p取模,指数对phi(p)取模,再计算乘方

  • EXGCD和逆元

   1.exgcd: 用于计算x,y  使得对于任意整数a,b, 存在一对整数x,y,满足ax+by=gcd(a,b)

    

 

    所以 :

              

1 int exgcd(int a,int b,int &x,int &y)
2 {
3     if(b==0) { x=1; y=0;return a; }
4     int d=exgcd(b,a%b,y,x);
5     y-=a/b*x;
6     return d;
7 }
8 //d=exgcd(a,b,x0,y0);

     调用函数可求得 ax + by = gcd (  x,  y ) 的一组特解,d 为 gcd ( a , b )

posted @ 2018-10-19 12:16  flowphyl  阅读(130)  评论(0编辑  收藏  举报