一.\(BSGS\)算法(大步小步算法)
求解:\[a^x\equiv b\pmod{c}\]
其中\(c\)为质数
我们把\(x\)拆为\(x = im - j\)。
那么:\(a^x\equiv b\pmod{c}\) ------->\(a^{im-j}\equiv b\pmod{c}\)
\(a^{im-j}\equiv b\pmod{c}\) --------> \(ba^j\equiv a^{im}\pmod{c}\)
显然\(m\)取\(\sqrt{c}\)最舒服,那么令\(m=\sqrt{c}\),
然后枚举\(i\)(\(i \leq \sqrt{c}\)),把\(a^{im}\)用\(map\)或者\(hash\)存起来。
这样我们再枚举\(j\),只需要检查\(ba^j\)是否已经存在即可,
假如存在,那么此时\(x=im-j\)即为方程的解。
代码参考:戳我!
二.卢卡斯定理(Lucas)
1.卢卡斯定理:
就一句话:
\[C_n^m \% p = C_{n\% p}^{m\%p}*C_{n/p}^{m/p}\]
其中\(p\)为质数,一般用于计算比较大的组合数。
2.扩展Lucas定理:
当\(p\)不为质数的时候,先唯一分解:
\[p = p_1^{k_1}*p_2^{k_2}....P_n^{k_n}\]
那么其实就是求解下面这个方程组中的\(ans\):
\(ans\equiv c_1\pmod{p_1^{k_1}}\)
\(ans\equiv c_2\pmod{p_2^{k_2}}\)
\(......\)
\(ans\equiv c_n\pmod{p_n^{k_n}}\)
其中\(c_1\)、\(c_2\)、\(...\)、\(c_n\)为对应\(C_n^m \% p_t^{k_t}\)的答案。
假设我们可以求得\(c_1\)、\(c_2\)、\(...\)、\(c_n\),那么直接\(CRT\)一波即可得到\(ans\)。
所以现在问题变为求解\(C_n^m\%p^k\)。 我们知道:\(C_n^m = \frac{n!}{m!(n-m)!}\)
所以其实我们就是要求\(n! \% p^k\)。这个东西这么求呢?
首先,我们等会是要求逆元的,所以应该要先把\(p\)提出来,等会算完逆元后再乘回去即可。
所以我们可以把上面的\(n!\)拆为:
\[n! = p^t*\lfloor \frac{n}{p} \rfloor !*G(n)\]
其中\(G(n)\)为不是\(p\)倍数的数的乘积,显然\(\lfloor \frac{n}{p} \rfloor !\)可以递归求解。
\(p^t\)是提出来的最后再一起算,所以我们只要考虑如何算\(G(n)\)。
观察到\(G(n) \% p^k\)是以\(p^k\)为周期的,所以肯定可以数论分块,分块搞一下即可。
最后考虑一下\(p^t\)这一项,一个\(\prod_{i=1}^{n}\)中约数\(p\)的个数为\(\sum_{r=1}^{p^r \leq n} {\lfloor \frac{n}{p^r}} \rfloor\),可以直接算出\(t\)。
然后就做完了,记得最后强行\(CRT\)一波合并\(c_i\)即可。
这里给出求解\(C_n^m\%p^k\)部分的代码:
注:代码中的pk代表p^k,是事先求好了的。
LL fac(LL n,LL p,LL pk) //计算(n!) % (p^k)
{
if(n==0)return 1;
LL res=1;
for(LL i=2;i<=pk;i++) //求解G(n)中的整块:
if(i%p)res=(res*i)%pk;
res=pow(res,n/pk,pk); //res = res^(n/(p^k)) //分块一波
for(LL i=2;i<=n%pk;i++)
if(i%p)res=(res*i)%pk; //求解G(n)中的余项。
return (res*fac(n/p,p,pk))%pk; //递归求解。
}
LL Calc(LL n,LL m,LL p,LL pk)
{
if(n
三.提取公因数
这个其实不能算是数论吧.... 但是这里列一个专题是因为它太重要了。
提取公因数与数论分块被称为数论两大套路(笔者自己yy不要管啦)
提取公因式衍生出来的是“考虑每一项对答案的贡献”,一般涉及这种思想的题目都是非常难的。
其实具体还是要见题拆题。这里给两个例子:
例子1
假如\(a^2-ab = E^2\) , 那么如何快速求解符合条件的\((a、b)\)二元组?
\(a^2-ab = a(a-b) = E^2\),所以\(a=F^2\) , \(a-b=S^2\)
所以\(F^2-b = S^2\),即得到:\(b = (F-S)(F+S)\)
枚举量一下子就大幅度的减少了。
例子2
求解\(\sum_{i=1}^n \sum_{j=1}^m gcd(i,j)\)。
把\(d=gcd(i,j)\)给提出来。
\[\sum_{i=1}^n \sum_{j=1}^m gcd(i,j) = \sum_{d=1}^{min(n,m)}d\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)=d] = \sum_{d=1}^{min(n,m)}d\sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor } \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor } [gcd(i,j)=1]\]
然后至于\(\sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor } \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor } [gcd(i,j)=1]\)怎么快速求见后面的莫比乌斯反演。
例子3
求解\(\sum_{d=1}^n \phi(d) \sum^{\lfloor \frac{n}{d} \rfloor}_{i=1} {\lfloor \frac{n}{id} \rfloor}\),多组数据。
令\(T = id\) , 然后把\(T\)给提出来。
\[\sum_{d=1}^n \phi(d) \sum^{\lfloor \frac{n}{d} \rfloor}_{i=1} {\lfloor \frac{n}{id} \rfloor} = \sum_{T = 1}^n{\lfloor \frac{n}{T} \rfloor} \sum_{d|T} \phi(d)\]
后面的\(\sum_{d|T} \phi(d)\)可以线性筛,具体见后面相关内容,从而使得询问时单组复杂度由\(O(n)\)变为了\(O(\sqrt{n})\)
四.莫比乌斯反演(\(Mobius\))
当一个函数\(F(n)\)很好求,而其可以写成其约数或倍数\(d\)的函数\(f(d)\),\(f(d)\)很不好求时,
我们可以通过莫比乌斯反演用\(F(n)\)反推\(f(d)\),从而实现快速求解\(f(d)\)。
其实就是容斥原理的体现,证明见这里 戳我!
莫比乌斯反演有两种形式:
1.约数形式:
若有\(F(n) = \sum_{d|n} f(d)\) 那么\[f(n) = \sum_{d|n} \mu(\frac{n}{d})*F(d)\]
2.倍数形式:
若有\(F(n) = \sum_{n|d} f(d)\) 那么\[f(n) = \sum_{n|d} \mu(\frac{d}{n})*F(d)\]
3.莫比乌斯函数:
莫比乌斯函数即为\(\mu(d)\),定义如下:
(1)若\(d=1\),那么\(\mu(d)=1\)
(2)若\(d=p_1p_2p_3...p_k\),\(p_1,p_2...\)均为互异素数,那么\(\mu(d)=(-1)^k\)
(3)其它情况下\(\mu(d)=0\)
莫比乌斯函数为积性函数,可以线性筛出,下面给出代码:
void Mobius(){
memset(Isprime,true,sizeof(Isprime));
mu[1] = 1; Isprime[1] = false;
for(int i = 2; i <= n; i ++){
if(Isprime[i]){prm[++cnt] = i; mu[i] = -1;}
for(int j = 1; prm[j]*i<=n && j <= cnt; j ++){
Isprime[i*prm[j]] = false;
if(i%prm[j] == 0){mu[i*prm[j]] = 0; break;}
else mu[i*prm[j]] = -mu[i];
}
}
}
4.莫比乌斯反演与\(\sum [gcd(i,j)=1]\)
求解\(gcd(i,j)\)相关问题是莫比乌斯反演最常见的应用。
当遇到涉及莫比乌斯反演的题目时,一般也是先把其转化为求\(\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)==1]\)
下面给出求解\(\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)==1]\)\((n\leq m)\)的莫比乌斯反演过程:
令\(f(d) = \sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)==d]\)
然后令:
\[F(n) = f(d)+f(2d)+...+f(kd)=\sum_{n|d} f(d)\]
所以\(F(d)\)即表示\(gcd(i,j)\)为\(d\)的倍数的二元组的个数。
那么显然\(F(d)\)非常好求:
\[F(d) = \lfloor \frac{n}{d} \rfloor * \lfloor \frac{m}{d} \rfloor\]
又因为\(F(n) = \sum_{n|d} f(d)\)
所以通过莫比乌斯反演得到:
\[f(n) = \sum_{n|d}^{d \leq n} \mu(\frac{d}{n})F(d)\]
所以:
\[f(1) = \sum_{i=1}^{n} \mu(i)F(i) = \sum_{i=1}^{n} \mu(i)\lfloor \frac{n}{i} \rfloor * \lfloor \frac{m}{i} \rfloor\]
先求一下\(\mu(i)\)的前缀和,然后数论分块就行了。
上面得到的关系式非常重要,你甚至可以把它记下来(n<=m):
\[\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)=1]=\sum_{i=1}^{n} \mu(i)\lfloor \frac{n}{i} \rfloor * \lfloor \frac{m}{i} \rfloor\]
5.莫比乌斯反演习题:
见莫比乌斯反演题目列表:[戳这里!] (http://www.cnblogs.com/GuessYCB/p/8277359.html)
五.积性函数线性筛 与 狄利克雷卷积
1.积性函数 与 线性筛
a.积性函数相关定义
(1)积性函数:
若存在函数\(f(x)\) ,当\((x,y)=1\)时 , 满足\(f(x*y)=f(x)*f(y)\),则称\(f(x)\)为积性函数。
(2)完全积性函数:
若对于任意\(x,y\),有\(f(x*y) = f(x)*f(y)\),则称\(f(x)\)为完全积性函数。
(3)常见的积性函数:
莫比乌斯函数\(\mu(i)\) 、 欧拉函数\(\phi(i)\)。
b.积性函数的线性筛(sieve)
完全积性函数的筛法就不讲了,直接乘起来即可。
那么对于积性函数\(f(x)\)的线性筛,我们要求下面几个东西有定义或很好求:
(1)\(f(1)\)
(2)\(f(p)\) , (\(p\)为质数)
(3)\(f(p^k)\) , (\(p\)为质数)
其中\(f(1) , f(p)\)一般为\(O(1)\)算,\(f(p^k)\)则一般从\(f(p^{k-1})\)推来。
那么假设我们已经求解的上面函数的取值,考虑如何筛。
由积性函数的定义我们可以知道\(f(x*y)=f(x)*f(y)\)的前提条件为\((x,y)=1\)。
所以当我们要筛一个\(f(n)\)时,我们要把\(n\)拆为两个互质的数\(x,y\)的乘积。
显然最优秀的办法就是让\(x\)取最小值因子,把最小质因子\(x^k\)分离出来,这样就可以套上线性筛了。
我们记\(low(i)\)表示\(i\)的最小质因子\(x\)的\(x^k\),
那么根据线性筛的原则,我们分两种情况讨论(\(i,prm[j]\)含义见素数线性筛):
(1)当\(i\%prm[j] != 0\)时
这太容易了不是吗,\(i\)与\(prm[j]\)互质,直接套定义即可。
\[f(i*prm[j]) = f(i)*f(prm[j]);low(i*prm[j]) = prm[j]\]
(2)当\(i\%prm[j]==0\)时
首先\(low(i*prm[j]) = low(i)*prm[j]\)这没有什么好说的吧。
然后:
第一种情况:\(low(i)=i\),那么\(i\)是\(p^k\)形式,用特殊方法计算。
第二种情况:\(low(i)!=i\),那么我们把\(prm[j]*i\)拆为两个互素的数,具体为把\(prm[j]\)给除干净:
\[f(i*prm[j] = f(i\ /\ low[i]) * f(low[i]*prm[j])\]
然后就没有了。 下面给出具体实现代码:
void sieve(){
low[1] = 1; f[1] = 对f(1)的特殊定义; tot = 0;
for(int x = 2; x <= n; x ++){
if(!Prime[x]){prm[++tot] = x; f[x] = 对f(p)的特殊定义; low[x] = x;}
for(int j = 1; j <= tot && x*prm[j] <= n; j ++){
Prime[x*prm[j]] = true;
if(x%prm[j] == 0){
low[x*prm[j]] = low[x] * prm[j];
if(x == low[x])
f[x*prm[j]] = 对f(p^k)的特殊定义;
else
f[x*prm[j]] = f[x/low[x]] * f[prm[j]*low[x]];
break;
}
low[x*prm[j]] = prm[j];
f[x*prm[j]] = f[x] * f[prm[j]] % mod;
}
}
return;
}
2.狄利克雷卷积
其实懂了积性函数的线性筛之后这玩意就是来搞笑的。
对于积性函数\(f(x)\)与\(g(x)\),它们的狄利克雷卷积也是积性函数。
其中它们的狄利克雷卷积长这样:
\[(f*g)(n) = \sum_{d|n} f(d) g(\frac{n}{d})\]
狄利克雷卷积的性质:
交换律:\((f*g) = (g*f)\)
结合律:\((f*g)*h = f*(g*h)\)
狄利克雷卷积自身不难,把它当做积性函数一样的线性筛即可。
六.杜教筛
....还不会,到时候回来补(先去搞点其他的换脑子啦):
留下学习资料:
http://blog.csdn.net/skywalkert/article/details/50500009
http://www.cnblogs.com/zhoushuyu/p/8301660.html