1.约束和定理
2.逆元
求逆元的2种模板
(1) exgcd 求逆元
x->a关于b的逆元
y->b关于a的逆元
typedef long long LL
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d)
{
if (!b) {d = a, x = 1, y = 0;}
else
{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p)
{//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
(2)快速幂+费马小定理求逆元
// 快速幂求逆元
LL pow_mod(LL a, LL b, LL p)
{//a的b次方求余p
LL ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
LL Fermat(LL a, LL p)
{//费马求a关于b的逆元
return pow_mod(a, p-2, p);
}
3.莫比乌斯反演
(1) 整除分块
可以用到整除分块的形式,大致是这样的:
打表:
对于每一个 我们可以通过打表(或理性的证明)可以发现:
有许多的值是一样的,而且它们呈一个块状分布;再通过打表之类的各种方法,我们惊喜的发现对于每一个值相同的块,它的最后一个数就是 。得出这个结论后,我们就可以做的O(
)处理了。
附一个整除分块的代码吧:
for(int l=1,r;l<=n;l=r+1) { r=n/(n/l); ans+=(r-l+1)*(n/l);//个数*值 }
(2) 与其他函数的联系
- 有时候,可能推出来的式子不一定就是一个很裸的整除分块,可能会与某些积性函数相乘,如:μ,,φ...... 这时候,我们就需要对这些函数统计一个前缀和。因为,每当我们使用整除分块跳过一个区间的时候,其所对应的函数值也跳过了一个区间。所以此时,就需要乘上那一个区间的函数值。
- (当然,如果当出题人想要考考你的数论能力的话,这时就不是统计前缀和这么简单了。可能O(n)线筛都会TLE,那么我们就需要杜教筛了)
- https://www.cnblogs.com/peng-ym/p/9446555.html
(3)莫比乌斯反演
题目
HDU 1452
大意:求2004^n的约束和
约束和+快速幂+逆元
#include<bits/stdc++.h> using namespace std; // 快速幂 long long pow_mod(long long a, long long b,long long p) {//a的b次方求余p long long ret = 1; while(b) { if(b&1)ret=(ret*a)%p; a=(a*a)%p; b>>=1; } return ret; } long long Fermat(long long a, long long p) {//费马求a关于b的逆元 return pow_mod(a, p-2, p); } int main() { int n; while(~scanf("%d",&n)) { if(n==0)break; long long a,b,c; a=pow_mod(2,2*n+1,29)-1; b=pow_mod(3,n+1,29)-1; c=pow_mod(167,n+1,29)-1; long long ans=(a*b*c*9)%29; printf("%lld\n",ans); } //printf("%lld",Fermat(332,29));==9 return 0; }
HDU 1695
大意:给出n、m、k ,求出1<=x<=n, 1<=y<=m 且gcd(x,y) == k 的(x,y)的对数