0.写在前面
因为费马小定理的使用需要满足两个数是否互质(数论中大部分定理都需要,so,我接下来讲的worth积累)
先补充筛法
1.求素数用到的方法
(1)普通枚举 枚举到sqrt(n)就好
(2)朴素筛法
通过对每个数有无非平凡因子来判断
朴素筛法 nlogn ,这个时间复杂度的计算有些复杂
如下
n/2+n/3+n/4+…+n/n;
n(1/2+1/3+1/4+…+1/n)
后面那一坨大致就约等于 ln(n) (学过数竞应该知道)
int a[maxn],b[maxn],n;
int cnt=0;
//筛出 2 到 n 中的所有素数
void naive_sieve(int n){
for(int i=2;i<=n;i++)
{
if(!a[i]) b[cnt++]=i;
for(int j=2*i;j<=n;j+=i)//从i+i往后筛所有的倍数
a[j]=1;
}
}
(3)埃式筛法
通过素因子来筛
int a[maxn],b[maxn],n;
int cnt=0;
//优化, nloglogn ,这里的计算跟上个差不多,埃式筛法
void naive_sieve(int n){
for(int i=2;i<=n;i++)
{
if(!a[i])
{
b[cnt++]=i;
for(int j=2*i;j<=n;j+=i)//将此循环体拿到if依据里面
//意思就是,在遍历筛的时候遇到的如果是合数就不用筛了,优化
a[j]=1;
}
}
}
(4)线性筛(欧拉筛)
void oula_sieve(int n)
{
int cnt=0;
for(int i=2;i<=n;i++)
{
if(!a[i]) b[cnt++]=a[i];
for(int j=0;b[j]*i<=n;j++)
{
a[b[j]*i]=1;
// 保证b[j]是i*b[j]1的最小素因子
if(i%b[j]==0) break;
}
}
}
大家可能对以上三种方法及其优化思路还有疑问,下面加深讲解
1.基本思想其实都是先筛掉有非平凡因数的合数筛掉,再进行存储
2.举下面 一个栗子
比如说我们要筛 12这个数
(1)朴素筛 : 除1外每个数都要去把12筛一遍
也就是我们扫到这些数都要去把12筛 : 2 3 4 6
(2)埃氏筛 : 除1外每个质因数都要去把12筛一遍
也就是我们扫到这些数都要去把12筛 : 2 3
(3)欧拉筛 :
可能有人不太懂
1–j代表的是下标
2–b[]存储找到的素数
代码中的第二重(if依据巧妙避开求重)可以让标记只让当前找到的素因数往后标记
3–还是举12的例子
12的最小质因数会将12筛出
也就是只有:2
4–总结欧拉筛:
每次用已筛出来的质数去筛更大的数,
每个合数只被它最小的质因子筛掉,
试想,如果26筛了12之后还没break,
而是用36筛掉18,那么18还会被29筛一次,就重复了
而根本原因就是6有2这个因子,
而36筛掉的数一定也有2这个因子,
3*6这个数应该被2这个因子筛掉,而不是3
然后是gcd
gcd(a,b)指的是a,的最大公约数
如果a,b互质那么 gcd(a,b)=1;
一般来讲我们求gcd是通过辗转相除法的
就是 gcd(a,b)=gcd(a,b%a);满足a>b
这里直接套一个递归就好了
int gcd(int a,int b)
{
return b == 0 ? a : gcd(b,a % b);
}
//这个玩意可以这么读:b == 0否?b == 0的话返回a,b != 0的话返回gcd(b,a%b)
//就是辗转相除,除到0了那么上一个除数就是最大公约数
int gcd(int a,int b)
{
if(b==0)
return a;
return (b,a%b);
}
1.内容
当gcd(a,p)=1时
a^(p-1)=1(mod p)
a的p-1次方取p的模为1
2.举例
如果现在我们要去求 2^100(mod 13)=?
很明显该数过大,不过我们首先可以考虑用二分的思想,一层一层取模运算。
但是,Sabrina提出了问题:有没有更好的办法呢?
肯定是有的
从费马小定理出发,我们是否可以将这个一百化为 n*(p-1)+k,n直接用100/12向下取整就好了,
这样的话,我们就直接考虑 2^4(mod 13)=?
Sabria听到后很开森,不过她仍然意犹未尽,于是有了下面这道例题
3.例题
传送门
今天星期六,S.和L.一起出去游玩,突然S.提出一个问题1^1 + 2^2 + 3^3 + … + N^N天后的哪一天?
L.一下子就解答了,你能吗?
输入
有多个测试用例。 第一行输入包含一个整数T,表示测试用例的数量。 对于每个测试用例:
只有一行包含一个整数N(1 <= N <= 1000000000)。
产量
对于每个测试用例,输出一个表示星期几的字符串。
样本输入
2
1
2
样本输出
Sunday
Thursday
暗示
一周包括周日,周一,周二,周三,周四,周五和周六。
Jīntiān xīngqíliù,11 + 22 + 33 +… + NN tiānhòu de nǎ yītiān?
Shūrù
yǒu duō gè cèshì yònglì. Dì yīxíng shūrù bāohán yīgè zhěngshù T, biǎoshì cèshì yònglì de shùliàng. Duìyú měi gè cèshì yònglì:
Zhǐyǒu yī xíng bāohán yīgè zhěngshù N(1 <= N <= 1000000000).
Chǎnliàng
duìyú měi gè cèshì yònglì, shūchū yīgè biǎoshì xīngqí jǐ de zìfú chuàn.
Yàngběn shūrù
2
1
2
yàngběn shūchū
xīngqírì
xīngqísì
ànshì
yīzhōu bāokuò zhōu rì, zhōuyī, zhōu’èr, zhōusān, zhōu sì, zhōu wǔ hé zhōu liù.
题解
Sabrina看到这道题有点感觉有点难了
但是一旁的同学笑了笑,这是一道非常水的题,用上费马小定理秒杀哦!
我们知道n^n%7= (n%7)^ n%7,令n%7=m,就相当于n-7*[n/7]
则原式=(m^ m%7)(m^ (n-m)%7)%7
举个例子,9 ^9%7=2 ^9%7=((2 ^2%7)(2 ^7%7)) %7,
所以只要让(2 ^7%7)这个部分等于1,
而且这一部分,2的幂肯定是7的倍数,那么循环节就出现了,循环节的开端为
m ^m%7(m<7)。
我们知道(2 ^a%7) ^b%7=x ^ab%7,让该公式为1,且ab为7的倍数,则a等于6(费马小定理),得ab的最小值为42,也就是要重复就经过了42种情况
,所以n^n%7的循环节为42
294=42*7,即为11 + 22 + 33 + … + NN %7的循环节
但是Sabrina还是有一点疑惑,于是有了下面几张图
这个题中我们的p也就是一周的天数7,最开始的形式:
1^1 2^2 3^3 4^4 5^5 6^6 7^7
8^8 9^9 10^10 11^11 12^12 13^13 14^14
15^15 16^16 17^17 18^18 19^19 20^20 21^21
22^22 23^23 24^24 25^25 26^26 27^27 28^28
29^29 30^30 31^31 32^32 33^33 34^34 35^35
36^36 37^37 38^38 39^39 40^40 41^41 42^42
43^43 44^44 45^45 46^46 47^47 48^48 49^49
这里就相当于n-7*[n/7]的过程
费马小定理转化后–>>(分别取6的模,然后来减掉)
1^1 2^2 3^3 4^4 5^5 6^0 0^1
1^2 2^3 3^4 4^5 5^0 6^1 0^2
1^3 2^4 3^5 4^0 5^1 6^2 0^3
1^4 2^5 3^0 4^1 5^2 6^3 0^4
1^5 2^0 3^1 4^2 5^3 6^4 0^5
1^0 2^1 3^2 4^3 5^4 6^5 0^0
1^1 2^2 3^3 4^4 5^5 6^0 0^1
最后一行重复,循环节长度为4
Sabrinadol懂了,你懂了吗
–