NOIP数学复习
来源:互联网 发布:嵌入式linux应用开发 编辑:程序博客网 时间:2024/05/12 12:44
NOIP中的数学相关知识
素数及其相关
a.判断素数 复杂度O(根号n)
bool prime(int x) { if(x == 0 || x == 1) return false; for(int i = 2; i * i <= x; i++) { if(x % i == 0) return false; } return true;
b.筛素数
埃氏筛法 复杂度O(n loglog n)
对于每个数p,会划掉p/n个数
#include<iostream>#include<cstdio>using namespace std;const int SIZE=1e7;int prime[SIZE];// 第i个素数bool is_prime[SIZE];//true表示i是素数int slove(int n){ int p = 0; for(int i = 0; i <= n; i++) is_prime[i] = true;//初始化 is_prime[0] = is_prime[1] = false;//0,1不是素数 for(int i = 2; i <= n; i++) { if(is_prime[i])//zkzk { prime[p++] = i;//计算素数的个数,也记录下了素数 for(int j = 2 * i; j <= n; j += i)// 除掉了i的倍数的数字 is_prime[j] = false; } } return p;}int main(){ int n; while(cin >> n) { int res = slove(n); cout << res << endl;//素数个数 for(int i = 0; i < res; i++)//列出素数 cout << prime[i] << endl; }}//zk:初始最小素数是2,将数据内2的所有倍数扔掉。此时3不能被更小的数整出,即为素数依次类推;
欧拉筛法 复杂度O(n)
luogu 线筛模板:
#include <cstdio>using namespace std;const int maxn=10000000;int n,m;int prime[maxn],flag[maxn];int tot;void get_prime(int n){ flag[0]=flag[1]=1;//不是素数 for (int i=2; i<=n; ++i) { if (!flag[i]) prime[++tot]=i; for (int j=1; j<=tot&&i*prime[j]<=n; ++j) { flag[i*prime[j]]=1; if (i%prime[j]==0) break;//prime[j]必定是prime[j]*i的最小因子;i中有因子prime[j],已被筛到一次 就退出找下一个i } }}int main(){ scanf("%d%d", &n, &m); get_prime(n); int t; for (int i=1; i<=m; ++i) { scanf("%d", &t); if (!flag[t]) printf("Yes\n"); else printf("No\n"); } return 0;}
2.区间筛素数
(poj2689)
筛[a,b)中的素数
因为b以内合数的最小质因数一定不超过sqrt(b),先分别做好[2,sqrt(b))的表和[a,b)的表,然后从[2,sqrt(b))的表中筛得素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是区间[a,b)内的素数。
用埃氏筛的原理:
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>using namespace std;typedef long long ll;const ll maxn=1e6+10;bool is_prime[maxn],is_p[maxn];//is_prime[]表示le~ri中下边位移后的素数判定(a位移1),is_p[]表示1~根号n中的素数判定 ll prime[maxn],sum;void get_prime(ll le,ll ri){ for(ll i=2;i*i<ri;i++) is_p[i]=true;//对[2,sqrt(b))的初始化全为质数,i要从2开始, 1不是素数 for(ll i=1;i<=ri-le;i++) is_prime[i]=true;//对下标偏移后的[a,b)进行初始化,i要从1开始 for(ll i=2;i*i<=ri;i++){ if(is_p[i])for(ll j=2*i;j*j<=ri;j+=i) is_p[j]=false;//筛选素数i的倍数 for(ll j=max(2LL,(le+i-1)/i) * i;j<=ri;j+=i) is_prime[j-le]=false;//(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选 } for(ll i=1;i<ri-le;i++) if(is_prime[i]) prime[++sum]=i+le;}int main(){ ll l,r; while(scanf("%lld%lld",&l,&r)){ sum=0; memset(prime,0,sizeof(prime)); get_prime(l,r); printf("%lld\n",sum); } return 0;}
3.分解质因数
基于唯一分解定理
n = P1^a1 * P2^a2 * …………* Pn^an(P1 < P2 < ……Pn),Pi为质数;
朴素法(可以先求出素数来优化一下)
void fj(int x) { for(int i = 2; i * i <= x && x > 1; i++) { while(x % i == 0) { if(!check[i]) zhi[++cnt] = i;//check判断有没有出现过 check[i]++; x /= i; if(x == 1) break; } }}
例题QwQ、Problem A. 最佳进制
快速幂
// a ^ b % modint ksm(int a,int b,int mod) { int ans=1; a%=mod while(b){ if(b&1)ans=(ans*a)%mod; b>>=1; a=(a*a)%mod } return ans;}
排列组合
组合
void init(){ f[0][0]=1; for(int i = 1; i <= inf; ++i){ f[i][0]=1; for(int j = 1;j <= i; ++j){ f[i][j] = f[i-1][j] + f[i-1][j-1]; } }}
next_permutation(a +1,a+1+n); STL全排列
同余
同余的性质
0.0
同余方程
欧几里得算法
好久之前的笔记——关于gcd,exgcd,cal
/*设两数为a、b(a>b),求a和b最大公约数(a,b)的步骤如下:
用a除以b,得a÷b=q……r1(0≤r1)。
若r1=0,则(a,b)=b;若r1≠0,则再用b除以r1,得b÷r1=q……r2 (0≤r2).
若r2=0,则(a,b)=r1,若r2≠0,则继续用r1除以r2,……
如此下去,直到能整除为止。其最后一个非零除数即为(a,b)。*/
//—————————————————————————————————-
#include<stdio.h>#define ll long long ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}int main(){ ll a,b; while(scanf("%lld%lld",&a,&b)!=EOF) { printf("%lld\n",gcd(a,b));//事实上如果 a 小于 b,那第一次就会先交换 a 与 b。 } return 0;}//--------------------------------------------------------void exgcd(ll a,ll b,ll& d,ll& x,ll& y){ if(!b){d=a;x=1;y=0;} else {exgcd(b,a%b,d,y,x);y-=x*(a/b);}}
//逆元
ll cal(ll a,ll m){ ll d,x,y; exgcd(a,m,d,x,y); return (x%m+m)%m;} int main(){ ll a,b,d,x,y; while(scanf("%lld%lld",&a,&b)!=EOF){ exgcd(a,b,d,x,y); printf("%lld*%lld+%lld*%lld=%lld\n",a,x,b,y,d); } return 0;}
/*
同余方程
先讲一下扩展欧几里德定律:
对于不完全为0的非负整数a,b,gcd(a, b)表示a, b的最大公约数,必定存在整数对x,y,满足a*x+b*y==gcd(a, b)。
证明:(转)
a*x1+b*y1=gcd(a, b);
b*x2+(a%b)*y2=gcd(b, a%b);
因为由欧几里德定理知:gcd(a, b)==gcd(b, a%b)
所以a*x1+b*y1=b*x2+(a%b)*y2; 因为r=a%b, r =a-k*b所以==>
a*x1+b*y1=b*x2+(a-k*b)*y2; 因为k=a/b;所以==>
a*x1+b*y1=b*x2+(a-(a/b)*b)*y2; 展开得到==>
a*x1+b*y1=b*x2+a*y2-b*(a/b)*y2;转换得到 ==>
a*x1+b*y1=a*y2+b*(x2-(a/b)*y2);
观察上式可知 x1=y2, y1=x2-a/b*y2;
由此可知x1,y1是由x2,y2得出来的,由此类推x2,y2是由x3,y3得出来的,
那什么时候是终止呢?也就是递归gcd(a, b)中b=0时;也就是说此时a的值就是要求得最大公约数
即gcd(a, 0)此时由扩展欧几里得定律a*x+b*y==gcd(a, b)
知 a*x+b*y=a;
解出x=1, y=0;
此时就是递归终止的地方:
——————–分界线————————
那么问题来了,这破东西有啥用呢
问的好,它可以用来求一个同余方程的解,也就是逆元
ax ≡ 1 (mod b),现在找x能够使这个式子成立
这个式子等价于ax+by=1
这不就是拓展欧几里得的表达式吗,从这里我们可以看出如果gcd(a,b)!=1那么这个方程就不会有解
所以说呢
形如a*x + b*y = c这样的式子,若c%gcd(a,b)==1,那么这个方程就会有解
PS:题目保证有解,所以不用判断了
但是一般题目里会让你求一个最小的x,当你用拓欧求出一个解时,一般会让你去找一个最小解,我们只需要对这个数取模b就行了(如果求正数,你只需要先加一个b,再取模行了,应该都知道吧)
代码如下
#include <cstdio>using namespace std;typedef ll ll;ll a,b,x,y;ll e_gcd(ll a,ll b,ll &x,ll &y){ if(!b) { x=1; y=0; return a; } ll ans=e_gcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-(a/b)*y; return ans;} int main(){ scanf("%lld%lld",&a,&b); e_gcd(a,b,x,y); printf("%lld",(x+b)%b); return 0;}
1.最大公因数
int gcd(int a,int b) { if(!b) return a; else return gcd(b, a % b);}
2.最小公倍数
gcd(a,b) * lcm(a,b) = a * b; lcm(a,b) = a * b / gcd(a,b);int lcm(int a,int b) { return a * b / gcd(a,b);}
霍dalao的丑字:
扩展欧几里得算法
void exgcd(int a, int b, int &d, int &x, int &y) { if(!b) {d = a, x = 1, y = 0, return;} exgcd(b, a % b, d , y, x); y -= x * (a / b);}
扩欧求解不定方程:
逆元
1.扩欧
int inv(int a, int n) { int d,x,y; exgcd(a,n,d,x,y); return (x % n + n) % n;}
2.费马小定理
a^(p-1) ≡1 (mod p)
int inv(int a, int n) { return ksm(a,n-2,n)}
递推规律
1.Catalan数
h(n)=(4n-2)/(n+1)*h(n-1)(n>1) h(0)=1 h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0) (n>=2) h(n)=C(2n,n)/(n+1)
2.错排公式
十本不同的书放在书架上。现重新摆放,使每本书都不在原来放的位置。有几种摆法?
f[1] = 0, f[2] = 1
f[i]=(i-1)*(f[n-1]+f[n-2])
3.斐波那契数列
f[1] = 1, f[2] = 1;
f[i] = f[i - 1] + f[i - 2]
5.除数函数
设 d(n)为 n 的所有因数的个数,由乘法原理可知,
d(n)=(a1 +1)(a2 +1)…(ak +1)。
4.秦九韶算法
int qing(int x){ int ans=a[n]; for(int i=n-1;i>=1;i--) ans=ans*x+a[i]; return ans;}
- 【NOIP复习】【数学】
- NOIP数学复习
- [NOIP 2014复习]第七章:数学
- NOIP复习-007——数学方法
- 数学复习(2017NOIP集训)
- 【NOIp复习】dp复习列表
- 【NOIp复习】数据结构复习列表
- NOIP快速幂复习
- NOIP复习篇
- 【NOIp复习】STL
- NOIP初赛总复习
- noip题目复习
- noip数论复习总结
- 【NOIP初赛】 组合数学
- [NOIP模拟][数学]Fibonacci
- 【NOIp复习】欧拉函数
- 【NOIp复习】网络流笔记
- NOIP 2016[图论复习]
- Spark源码无法下载
- mysql忘记密码
- LightOJ-1336
- fedora 启动react native时报aapt相关的错误
- Java23种设计模式——装饰模式
- NOIP数学复习
- Error[As001]: Invalid syntax
- Apache Maven、Maven仓库、Jcenter仓库
- php中fastcgi
- 设置dos运行框
- 解决Python2.7的UnicodeEncodeError: ‘ascii’ codec can’t encode异常错误
- Springmvc框架(入门程序)
- python3学习
- string find的用法详解