1.素数的判定
找1-n中的素数,有两种方法:
①O(nlogen)
开bool型数组a:i是合数,值为true;反之为false。
如果是素数,就把它放入素数队列,并把它所有的倍数标为true。
②O(n)
开bool数组a,定义和上面的一样。
在哪里被筛出来只和其最小的素因数有关。
num = 0;
memset(data, 0, sizeof(data));
data[1] = 1;
for(i=2; i<N; i++)
{
//data[i]为1表示i不是素数,为0表示i是素数
if( !data[i] )
prime[num++] = i;
//素数筛选
for(j=0; j<num&&i*prime[j]<N; j++)
{
data[i*prime[j]] = 1;
/*
i整除prime[j]便可退出,因为 i*prime[j+k](k>0) 一定会在后面被标记到
证明:
令i = prime[j]*x (整除)
i*prime[j+k] = prime[j]*x * prime[j+k] = prime[j] * (x*prime[j+k])
显然x*prime[j+k] > prime[j]*x = i 而 prime[j]为素数
当i增大到 x*prime[j+k] 便会标记到 prime[j] * (x*prime[j+k]) = i*prime[j+k]
所以 i*prime[j+k] 一定会在后面被标记到
*/
if( i%prime[j] == 0 )
break;
}
}
/*
在素数筛选中,合数只被标记一次,故里面总的循环次数接近N,加上外循环N次,时间复杂度为O(2n)即O(n)
*/
2.同余
余数:除数是正整数:a = kq + r,余数是r
同余:如果a % k = b % k;记做a三b(mod k)
同余的性质:
a( mod k)+b(mod k) 三 (a+b)(mod k);(加减)
a*b≡á*m (mod d )
裴蜀定理:
ax+by = c有整数解,充要条件:gcd(a,b)| c //gcd是最大公约数,c能被ab的最大公因数整除。
内容:ax + by = gcd(a,b) 有整数解。
逆元:
ax = 1(mod b)。x是a关于b的逆元。
欧几里得:
http://blog.csdn.net/zhjchengfeng5/article/details/7786595
--------------------------------------------------------------------------------------------------
欧拉函数:是小于或等于x的正整数中与x互质的数的数目
容斥原理:例如在两个集的情况时,我们可以透过将 {|A|} 和 {|B|} 相加,再减去其交集的基数,而得到其并集的基数(元素数量)。
1. 将n表示成素数的乘积: n = p1 ^ k1 * p2 ^ k2 * ... * pn ^ kn(这里p1, p2, ..., pn是素数)
每个p对应一个集合,是可以被p整除的数字集合。
欧拉函数= x-card总
欧拉函数(ab)= 欧拉函数(a)*欧拉函数(b)
如果求1-n所有数的欧拉函数?
https://yq.aliyun.com/articles/15314
/*线性筛O(n)时间复杂度内筛出maxn内欧拉函数值*/
int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因数,p是素数,pt是素数个数
int make()
{
phi[1]=1;
int N=maxn;
int k;
for(int i=2;i<N;i++)
{
if(!m[i])//i是素数
{p[pt++]=m[i]=i,phi[i]=i-1;}
for(int j=0;j<pt&&(k=p[j]*i)<N;j++)
{
m[k]=p[j];
if(m[i]==p[j])//为了保证以后的数不被再筛,要break
{
phi[k]=phi[i]*p[j];
/*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/
break;
}
else
phi[k]=phi[i]*(p[j]-1);//积性函数性质,f(i*k)=f(i)*f(k)
}
}
}
sg函数
https://zhuanlan.zhihu.com/p/20611132
http://web.mit.edu/sp.268/www/nim.pdf
https://www.youtube.com/watch?v=iyA6y6PKiC4