『正睿OI 2019SC Day7』
<更新提示>
<第一次更新>
<正文>
简单数论
质因子分解
素性测试
素性测试指的是对一个正整数是否为质数的判定,一般来说,素性测试有两种算法:
\(1.\) 试除法,直接尝试枚举因子,时间复杂度\(O(\sqrt n)\)。
\(2.\) \(Miller-Rabin\)算法,利用费马小定理和二次探测定理对素数进行测试,有小概率误判,时间复杂度\(O(log_2n)\)。
\(Code:\)
inline bool judge(long long x,long long p)
{
if ( x % p == 0 || quickpow( p%x , x-1 , x ) != 1 ) return false;
register long long k = x-1 , val;
while ( ( k & 1 ) == 0 )
{
val = quickpow( p%x , k>>=1 , x );
if ( val != 1 && val != x-1 ) return false;
if ( val == x-1 ) return true;
}
return true;
}
inline bool MillerRabin(long long x)
{
if ( x == 2 ) return true;
if ( x < 2 || ( x & 1 ) == 0 ) return false;
for (int i=0;i<10;i++)
{
if ( x == P[i] ) return true;
if ( !judge( x , P[i] ) ) return false;
}
return true;
}
质因子分解
质因子分解则指的是对一个正整数按照算术基本定理的形式进行分解,也有两种常用算法:
\(1.\) 试除法,直接尝试枚举因子,时间复杂度\(O(\sqrt n)\)。
\(2.\) \(Pollard's\ Rho\)算法,配合\(Miller-Rabin\)算法对整数进行随机化分解,期望时间复杂度\(O(\sqrt [4]{n}log_2n)\)。
\(Code:\)
inline long long Euclid(long long a,long long b) { return b == 0 ? a : Euclid(b,a%b); }
inline long long Random(void) { return ( 0LL + rand() ) << 30 | rand(); }
inline void PollardsRho(long long n)
{
if ( n == 1 ) return;
if ( MillerRabin( n ) ) { ans = max( ans , n ); return; }
long long x = Random() % n , c = Random() % n , y = x;
for (int i=2,k=2;true;i++)
{
register long long val = Euclid( n + y - x , n );
if ( val > 1 && val < n )
return PollardsRho(val) , PollardsRho(n/val);
if ( i == k ) k <<= 1 , y = x;
x = ( quickmul( x , x , n ) + c ) % n;
if ( x == y ) break;
}
return PollardsRho( n );
}
数论算法
欧几里得算法
利用辗转相除法求两个数的最大公约数,时间复杂度\(O(log_2n)\)。
\(Code:\)
inline int Euclid(int a,int b) { return b == 0 ? a : Euclid(b,a%b); }
扩展欧几里得算法
利用欧几里得算法求不定方程的特解,时间复杂度\(O(log_2n)\)。
\(Code:\)
inline int Extended_Euclid(int a,int &x,int b,int &y,int c)
{
if ( b == 0 ) { x = c/a , y = 0; return a; }
else
{
int p = Extended_Euclid(b,x,a%b,y,c);
int x_ = x , y_ = y;
x = y_ , y = x_ - a / b * y_;
return p;
}
}
类欧几里得算法
利用整除拆分技巧计算整除求和式,时间复杂度\(O(log_2n)\)。
\(Code:\)
inline long long f(long long a,long long b,long long c,long long n)
{
if ( a == 0 ) return ( n + 1 ) * ( b / c ) % Mod;
if ( a >= c || b >= c )
return ( f( a%c , b%c , c , n ) + n * ( n + 1 ) % Mod * INV2 % Mod * ( a / c ) % Mod + ( n + 1 ) * ( b / c ) % Mod ) % Mod;
long long val = ( a * n + b ) / c;
return ( ( n * val % Mod - f( c , c - b - 1 , a , val-1 ) ) % Mod + Mod ) % Mod;
}
中国剩余定理
利用公式计算线性同余方程组的特解,要求模数互质,时间复杂度\(O(nlog_2n)\)。
\(Code:\)
inline void CRT(void)
{
m_ = 1;
for (int i=1;i<=n;i++)
m_ *= m[i];
for (int i=1;i<=n;i++)
M[i] = m_ / m[i];
for (int i=1;i<=n;i++)
{
long long y;
Exeuclid(M[i],t[i],m[i],y,1);
ans += a[i]%m_ * M[i]%m_ * t[i]%m_;
ans %= m_;
}
}
拓展中国剩余定理
利用扩展欧几里得算法每次求一个同余方程的解,然后依次合并,从而求得线性同余方程组的解,不要求模数互质,时间复杂度\(O(nlog_2n)\)。
\(Code:\)
inline long long ExCRT(void)
{
long long m_ = m[1] , x = r[1];
for (int i=2;i<=n;i++)
{
long long x_,y_;
if ( ( r[i] - x ) % Euclid( m_ , m[i] ) ) return -1;
long long p = Exeuclid( m_ , x_ , m[i] , y_ , r[i] - x );
long long Mod = m[i] / p;
//要对当前的解先取模,防止爆longlong
x_ = ( x_ % Mod + Mod ) % Mod;
x += x_ * m_;
m_ = m_ * m[i] / p;
x = ( x + m_ ) % m_;
}
return x;
}
BSGS算法
利用分块思想求解离散对数问题的解,要求模数与底数互质,时间复杂度\(O(\sqrt n)\)。
\(Code:\)
inline long long Baby_Step_Giant_Step(long long a,long long b,long long p)
{
map < long long , long long > hash; hash.clear();
long long t = (long long)sqrt(p) + 1 , mul = 1;
b %= p;
for (int j=0;j<t;j++)
{
hash[ mul * b % p ] = j;
mul = mul * a % p;
}
if ( a % p == 0 ) return b == 0 ? 1 : -1;
a = 1;
for (int i=0;i<=t;i++)
{
long long j = ( hash.find(a) != hash.end() ? hash[a] : -1 );
if ( j >= 0 && i * t - j >= 0 ) return i * t - j;
a = a * mul % p;
}
return -1;
}
ExBSGS算法
利用同余性质缩小模数规模,直至模数与底数互质,使用\(BSGS\)算法求解离散对数,时间复杂度\(O(\sqrt n)\)。
\(Code:\)
inline long long ExBSGS(long long a,long long b,long long p)
{
if ( b == 1 ) return 0;
long long cnt = 0 , d , k = 1;
while ( ( d = Euclid(a,p) ) ^ 1 )
{
if ( b % d ) return -1;
b /= d , p /= d , ++cnt;
k = k * ( a / d ) % p;
if ( k == b ) return cnt;
}
unordered_map < long long , long long > Hash; Hash.clear();
long long t = (long long)sqrt(p) + 1 , mul = 1;
for (int j=0;j<t;j++)
{
Hash[ mul * b % p ] = j;
mul = mul * a % p;
}
for (int i=0;i<=t;i++)
{
long long j = ( Hash.find(k) != Hash.end() ? Hash[k] : -1 );
if ( j >= 0 && i * t - j + cnt >= 0 ) return i * t - j + cnt;
k = k * mul % p;
}
return -1;
}
原根
分解模数可以判定原根的存在性,同时可以根据欧拉定理求解原根。
\(Code:\)
pending further supplement
二次剩余
如果存在原根,则可以利用\(BSGS\)算法计算二次剩余,时间复杂度\(O(\sqrt n)\)。
\(Code:\)
pending further supplement
\(Tonelli–Shanks\)算法可以在\(O(log^2n)\)的时间内计算二次剩余。
\(Code:\)
pending further supplement
\(Cipolla\)算法可以在\(O(log_2n)\)的时间内计算二次剩余。
\(Code:\)
pending further supplement
数论函数
定义和概念
数论函数:定义域为正整数集,陪域为复数域的函数。
积性函数:对于任意\(a,b\in N^+,gcd(a,b)=1\),有\(f(ab)=f(a)f(b)\)的数论函数\(f\)被称为积性函数。
完全积性函数:对于任意\(a,b\in N^+\),有\(f(ab)=f(a)f(b)\)的数论函数\(f\)被称为完全积性函数。
积性函数的性质
\(1.\) 设\(n=\prod p_i^{a_i}\),则有\(f(n)=\prod f(p_i^{a_i})\)。
\(2.\) 若数论函数\(f,g\)均为积性函数,则\(f*g,f/g\)也均为积性函数。
狄利克雷卷积
对于数论函数\(f,g\),我们定义\(f\)和\(g\)的\(dirichlet\)卷积为:
\]
狄利克雷卷积的性质
\(1.\) 交换律:\(f\times g=g\times f\)。
\(2.\) 结合律:\((f\times g)\times h=f\times (g\times h)\)。
\(3.\) 分配律:\(f\times (g+h)=f\times g+ f\times h\)。
\(4.\) 单位元:\(f\times \epsilon=f\)。
\(5.\) 积性性:若函数\(f,g\)是积性函数,则\(f\times g\)也是积性函数。
莫比乌斯反演
莫比乌斯定理:若\(g=f\times I\),则\(f=g\times \mu\)。
证明:
\]
底和顶
\(1.\) \(x\geq n⇔\lfloor x\rfloor\geq n\)。
\(2.\) \(x> n⇔\lceil x\rceil> n\)。
\(3.\) \(x\leq n⇔\lceil x\rceil\leq n\)。
\(4.\) \(x< n⇔\lfloor x\rfloor< n\)。
\(5.\) 对于\(i\in[1,n]\),\(\lfloor \frac{n}{i} \rfloor,\lceil \frac{n}{i} \rceil\)都只有\(O(\sqrt n)\)种不同的取值。
杜教筛
对于计算数论函数\(f\)的前缀和,如果我们能够找到合适的函数\(g\),并能快速计算函数\(g\)和函数\(f\times g\)的前缀和,那么我们就可以快速计算函数\(f\)的前缀和。
公式:
\]
另一种形式,设\(S(n)=\sum_{i=1}^nf(i)\),那么有:
\]
可以用整除分块和记忆化搜索来计算,当我们线性筛预处理前\(n^{\frac{2}{3}}\)个前缀和时,杜教筛的时间复杂度为\(O(n^{\frac{2}{3}})\)。
\(Code:\)
inline pll BishopSieve(int n)
{
if ( n <= m ) return make_pair( phi[n] , mu[n] );
if ( sum.count( n ) ) return sum[n];
long long res1 = 1LL * n * ( n + 1 ) / 2 , res2 = 1;
for (int l=2,r;l<=n;l=r+1)
{
r = n/l ? min( n/(n/l) , n ) : n;
pll val = BishopSieve( n/l );
res1 -= 1LL * ( r - l + 1 ) * val.first;
res2 -= 1LL * ( r - l + 1 ) * val.second;
}
return sum[n] = make_pair( res1 , res2 );
// 求欧拉函数和莫比乌斯函数的前缀和
}
总结
感觉其实数论算法还有不少没有学,并且最大的问题就是做的题不够多,很多经典的套路还不够熟练,尤其是数论函数这一块。再就是代码不够熟练,还需要多刷题。
<后记>
『正睿OI 2019SC Day7』的更多相关文章
- 『正睿OI 2019SC Day8-Day17』
于是就迎来\(10\)天的自闭考试了,每天写点小总结吧. Day8 第一天就很自闭啊,考题分别是数学题+建模题+图论. 前两道题都没有什么算法,但是难度还是有的,于是就做不太出来,特别是第一题.第二题 ...
- 『正睿OI 2019SC Day5』
网络流 网络流的定义 一个流网络\(G=(V,E)\)为一张满足以下条件的有向图: 每一条边有一个非负容量,即对于任意\(E\)中的\((u,v)\) , 有\(c(u,v)\geq0\). 如果\( ...
- 『正睿OI 2019SC Day4』
总结 今天是一场欢乐的\(ACM\)比赛,于是我队得到了全场倒数的好排名. 好吧,其实还是怪自己不能怪队友啦.对于\(ACM\),可能最主要的还是经验不足,导致比赛的时候有点紧张.虽然队友为了磕一道题 ...
- 『正睿OI 2019SC Day1』
概率与期望 总结 老师上午几乎是在讲数学课,没有讲什么和\(OI\)有关的题目,所以我就做了一点笔记. 到了下午,老师讲完了有关知识点和经典模型,就开始讲例题了.前两道例题是以前就做过的,所以没有什么 ...
- 『正睿OI 2019SC Day6』
动态规划 \(dp\)早就已经是经常用到的算法了,于是老师上课主要都在讲题.今天讲的主要是三类\(dp\):树形\(dp\),计数\(dp\),\(dp\)套\(dp\).其中计数\(dp\)是我很不 ...
- 『正睿OI 2019SC Day3』
容斥原理 容斥原理指的是一种排重,补漏的计算思想,形式化的来说,我们有如下公式: \[\left | \bigcup_{i=1}^nS_i \right |=\sum_{i}|S_i|-\sum_{i ...
- 『正睿OI 2019SC Day2』
分治 普通分治 普通分治是指针对序列或平面问题的分治算法. 思想 普通分治的思想是指将一个序列问题或平面问题通过某种划分方式划分为若干个子问题,直到子问题规模足够小,可以直接回答,再通过合并得到原问题 ...
- 10.23 正睿停课训练 Day7
目录 2018.10.23 正睿停课训练 Day7 A 矩形(组合) B 翻转(思路) C 求和(思路 三元环计数) 考试代码 B1 B2 C 2018.10.23 正睿停课训练 Day7 期望得分: ...
- 正睿OI DAY3 杂题选讲
正睿OI DAY3 杂题选讲 CodeChef MSTONES n个点,可以构造7条直线使得每个点都在直线上,找到一条直线使得上面的点最多 随机化算法,check到答案的概率为\(1/49\) \(n ...
随机推荐
- 如何做一个跨平台的游戏App?
如何做一个跨平台的游戏App? iOS和安卓系统上的应用程序,根据提供的内容不同,按照开发方式和用户体验不同,可区分为app和游戏: 首先从开发方式不同来说明,app开发一般是用操作系统官方提供的开发 ...
- 七月伊始 LeetCode算法总结
七月伊始 早上买了LeetCode的课程,解锁了付费题目,付费倒逼学习: 意识到这么久学习的东西,都是写在自己的笔记, 如今希望自己能够用自己拙笔记录这个学习和总结的过程. 队列的学习 设计循环队列 ...
- 前端性能优化 http请求的过程及潜在的优化点
CS架构:比如我们的代码开发好,打包成apk,发布到平台,那么最终怎么运行到用户的手机上呢,用户首先需要从相关的应用商城下载这个apk包,并且运行这个 apk 包,那么这个 apk 包就会被解压,最后 ...
- django中运行定时任务脚本
需要使用到django_apscheduler模块,因此先安装: pip install django-apscheduler 然后在工程的settings.py文件中的INSTALLED_APPS模 ...
- Xcode添加库文件framework (转)
首先需要了解一下iOS中静态库和动态库.framework的概念 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用. 什么时候我 ...
- python--协程知识初识
线程和进程的操作是由程序触发系统接口,最后的执行者是系统:协程的操作则是程序员. 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续).协程 ...
- 关于时间排序在ios中失效的处理方法
上个月公司做项目的时候在列表排序的时候产品加了一个需求,通过点击量,发布时间,评论量进行筛选的一个需求. 一开始在电脑上测试基本没问题,然后我也就放下了这个按耐不住的小心脏,然后在完成所有模块后 sh ...
- Echarts数据更新大坑
今天使用了一个Echarts来实现柱状图和直线图统计组合,每次通过axios(ajax库)来请求新数据来刷新数据,但是发现请求数据确实是对应变化到了options变量中,后台数据条数只有一条,但是图表 ...
- Linux安装vim,解决vim: command not found
1,输入rpm -qa|grep vim 命令, 如果 vim 已经正确安裝,会返回下面的三行代码: root@server1 [~]# rpm -qa|grep vim vim-enhanced-7 ...
- 监听浏览器tab选项卡选中事件,点击浏览器tab标签页回调事件,浏览器tab切换监听事件
js事件注册代码: <script> document.addEventListener('visibilitychange',function(){ //浏览器tab切换监听事件 if( ...