收藏 分享(赏)

NOIP之数论与数论算法.pdf

上传人:精品资料 文档编号:10241200 上传时间:2019-10-24 格式:PDF 页数:10 大小:250.14KB
下载 相关 举报
NOIP之数论与数论算法.pdf_第1页
第1页 / 共10页
NOIP之数论与数论算法.pdf_第2页
第2页 / 共10页
NOIP之数论与数论算法.pdf_第3页
第3页 / 共10页
NOIP之数论与数论算法.pdf_第4页
第4页 / 共10页
NOIP之数论与数论算法.pdf_第5页
第5页 / 共10页
点击查看更多>>
资源描述

1、1 数论与数论算法 一、 质数 与质因 数 分解 1. 质数 : 也称素数, 指除 1 和它本身以外 没有其他因数的正整数 。 素数有无穷多 个。 1 不 是素数。 2. 质因 数分解 : 任意一个大于 1 的正整数都可以唯一分解成若干个质数相乘的形式。即: 3. 【 例题 1 】 已知正整数 N 是两个不同质数的乘积, 请求出较大的那个质数 (洛谷 1075) 。 提示:若 P、Q 为质数, 令 N = P * Q ,则 N 除 1 和它本身 以外,有且仅有 P、 Q 两个因 数。这也是目前主流的“非对称加密算法”R S A 算法的实现原理。 a 2 *3 *5 * 7 .(1b c d =

2、 0 ) bcd A Aa 为 大于 的正整数,其中 、 、 、 #include using namespace std; int main() i n tn=0 ; i n ti=2 ; cin n; / 找出n 的其中一个质因数 w h il e(n%i! =0) i+; i n tk=n/i ;/ / 求出n 的另一个质因数 / 求较大的那个质因数 i f(ki) k=i; cout k; return 0; 2 4. 【例题 2 】 对 N !进行质因数分解, 并求出每个质因数的个数 ( N int cnt10001 = 0; / 定义数组,保存每个质因数的个数 / 对给定的整数d

3、进行质因数分解 void seprate(int d) int factor = 2; while( d = factor) i f(d%f a ct or! =0) factor +; continue; cntfactor +; d=d/f a ct or ; int main() i n tn=0 ; scanf(“%d“, / 从2 到n 依次进行质因数分解 / 因为n ! =2*3*4* . .* n f o r(i n ti=2 ;i0) printf(“%d %dn“, i, cnti); return 0; 3 二、 质数 筛选( 求 1 到 N 的所 有质 数 ) 1. 【

4、试除法】: 使用 2 到 s q r t ( x ) 试除 x ,如 果 x 不存 在因 数则表 示 x 是质 数; 如果 x 有 因数则表示 x 不是质数。时间复杂度为:() Onn 2. 【 例题 1 】求第 k 小的素数 #include #include int main() i n tn=0 ,f=0 ; scanf(“%d“, for ( int x = 2; x = n; x+ ) f=1;/ / 将标记变量f 设为1 ,默认x 是质数 for ( int i = 2; i = sqrt(x); i+ ) i f(x%i= =0) / 如果找到x 有因数,则表明x 不是质数,将标

5、记变量设为0 ,跳出循环 f=0; break; i f(f= =1) printf(“%d “, x); return 0; / 部 分代 码已省 略 i n tx=2 ,n=1 ;/ /n 表示当前已求出的素数是第几个,x 表示当前被试除的整数 w h il e(nk) x+ ; f=1; for ( int i = 2;i = sqrt(x);i+) i f (x%i= =0 ) f=0; break; i f(f= =1) n +; printf(“%d“,x);4 3. 【 埃氏筛选法 】:由 质因数分 解定理, 可以得出 ,任意合 数都可以 分解成至 少两个质数 的乘积, 所以质数

6、是不能 被再分的 。 如果 x 是质数, 那么 2 * x、 3*x、 4*x、 必然都 不是质数。我们可利用此规律筛选出 N 以内的素数。时间复杂度为: (l o g l o g) On n 提示:假设 N 的值为 11,其对应的筛选过程如下: 第 1 轮筛选:2、3、4 、5、6 、7、8 、9、1 0 、1 1 (标记 4、6、8、1 0 不是素数) 第 2 轮筛选:2、3、4 、5、6 、7、8 、9 、1 0 、1 1 (标记 9 不是素数) 第 3 轮筛选:2、3、4 、5、6 、7、8 、9 、1 0 、1 1 (标记 10 不是素数) 因此输出结果为:2、3、5、7、1 1 4

7、. 【 练习 1 】线性筛素数(洛谷 3383) 5. 【 练习 2 】素数个数(洛谷 3912) #include #include #include int f10000010 = 0; / 素数标记数组, 若fi != 0, 则表示i 是素数 int main() i n tn=0 ; scanf(“%d“, memset( / 1 、假设n 以内的所有整数都是素数 f 1=0 ;/ /2 、整数1 不是素数 for ( int i = 2; i = sqrt(n); i+ ) i f(f i= =0) continue; / 3 、素数的整数倍必然不是素数 f o r(i n tj=2

8、* i;j =n ;j + =i) fj = 0; / 4 、输出所有的素数 for ( int i = 2; i = n; i+ ) i f(f i! =0) printf(“%d “, i); return 0; 5 三、 同余 模运算 1 . 模运算的基本规则如下: 加 法 : ( a+b )%p=( a%p+b%p )%p 减 法 : ( a-b )%p=( a%p-b%p )%p 乘 法 : ( a*b )%p=( a%p*b%p )%p 幂运算:a b %p=( ( a%p ) b )%p 交换率:( a + b) %p=( b+a )%p ( a*b )%p=( b*a )%p

9、结合率:( ( a + b ) %p+c )%p=( a+( b + c )%p )%p ( ( a * b )%p*c )%p=( a*( b * c )%p )%p 分配率:( ( a + b)%p*c )%p=( ( a*c )%p+( b*c )%p )%p 2. 【 例题 1 】给定一个整数 N,请求出 N 模 K 的余数。1 #include int main() char n100 = 0; l o ngl o ngk=0 ; scanf(“%s“, n); scanf(“%lld“, int len = strlen(n); l o ngl o nga n s=0 ,d=1 ;

10、 for ( int i = len 1 ;i =0 ;i ) d=d%k ;/ / 避免数据溢出 ans += (ni 0 )*d%k ; ans = ans % k; / 避免数据溢出 d=d*1 0 ; printf(“%lld“, ans); return 0; 6 四、 整数 的二进 制 分解 与快速幂 1. 整数 的二进 制分 解:任意整数都可以唯一分解成若干个二次幂的和。即: 2. 【 例题 1 】求 A*B 模 P,1 #include using namespace std; int main() l o ngl o nga=0 ,b=0 ,p=0 ,t=0 ; c i n

11、a b p ; t=a ; long long ans = 0; w h il e(b! =0) i n tx=b/ / 判断b 以二进制形式表示时 ,最末一位是否为1 i f(x= =1 ) ans = (ans + k)%p; t=( t*2 )%p ;/ / 后一项是前一项的两倍:t ( n)=2*t ( n 1) b=b 1 ;/ / 移除最末一位 ,将倒数第2 位变成最末一位 cout a n s % p ; retu rn 0 ; 7 参考代码如下: 4. 【 练习 】NOIP2013TGD1T 1-转圈游戏(洛谷 1 9 6 5 ) 五、 欧几 里德与 扩 展欧 几里德算 法 1

12、. 欧几里德算 法:又 称辗转相 除法,通 常用于 快速求解两个正整 数 a ,b 的最 大公因数 。 计算公式:g c d ( a , b ) = g c d ( b , a % b )。算法思路如下: 第 1 步:输入整数 a、b;若 a int main() l o ngl o nga=0 ,b=0 ,p=0 ; scanf(“%lld %lld %lld“, long long ans = 1%p; / 若b 的值为0, 则ab 的值为1 l o ngl o ngt=a ; w h il e(b) i f(b / t(n) = (t(n 1)2 / p 和a 的最大值都为109, 所以

13、t*t 不会超过long long 的存储范围 t = (t * t)%p; b =1 ; printf(“%lldn“, ans%p); return 0; 8 欧几里德算法的递归实现如下: 欧几里德算法非递归实现如下: #include long long gcd(long long a, long long b) i f(b= =0) return a; return gcd(b, a%b); int main() l o ngl o ngm=0 ,n=0 ; scanf(“%lld %lld“, / 输入m ,n ;求它们的最大公因数 i f(m int main() l o ngl

14、o ngm=0 ,n=0 ; scanf(“%lld %lld“, / 输入m ,n ;求它们的最大公因数 i f(mn) long long tmp = m; m=n; n = tmp; l o ngl o ngr=m%n ; w h il e(r! =0) m=n; n=r; r=m%n; printf(“%lld“, n); return 0; 9 2. 扩展 欧几里 德算 法: 对于任意不完全为 0 的非负整数 a、 b, 必然存在整数 x、 y, 满足: 证明过程如下: ( 1 )、若 b 等于 0,显然存在 x = 1 、y = 0 ,使得 ( 2 )、若 b 0 ,由欧几里德算法

15、可得: ( 3 )、假设存在整数 x、y 满足: ( 4 )、又因为: 令: 则就可以得到: 对欧几里德算法的递推过程运用数学归纳法,可得定理成立。 , , % gcd a b gcd b a b * * , ax by g c dab *1 0 * 0 , 0 ag c d a * % * , % bxabyg c dbab * % * b* x +(a - b* / )*y * % * = a * y - b * ( x - / *) bx a by ab bx a by aby /* xy y xaby * gcd( , ) axby ab 10 3. 【 扩欧 算法练 习 1 】扩展欧

16、几里德,参考代码如下: 4. 【 扩欧 算法练 习 2 】同余方程(洛谷 1 0 8 2 ) #include / a * x + b*y = gcd(a, b) / 递推过程:x(n) = y(n 1) ;y(n) = x(n 1) (a/b)*y(n 1) long long exgcd(long long a, long long b, long long y=0; return a; long long d = exgcd(b, a%b, x, y); long long t = x; x=y; y=t (a/b) * y; return d; int main() long long a = 0, b = 0, x = 0, y = 0; scanf(“%lld %lld“, exgcd(a, b, x, y); printf(“%lld %lld“, x, y); return 0;

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报