数学这个坑实在太大了,说白了是我太弱了
联赛考的:同余(解方程+逆元),欧拉函数,筛素数(这个过了),组合数,矩阵乘+快速幂,高斯消元
一点点把板子都总结一下。
同余方程:
首先是解线性同余的板子。
p*a+q*b=gcd(a,b)=gcd(b,a%b)=p*b+q*a%b=p*b+q*(a-a/b*b)=q*a+(p-a/b*q)*b;
根据这个式子得到。。
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int c=exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-a/b*y;
return c;
}
求逆元
概率题经常用到。
这里提两种算法。
1.求单值的。
ll ny(int a,int b,int c)
{
if(!a)return -1;
else if(!(c%a))return c/a;
ll t=ny(b%a,a,((-c%a)+a)%a);
if(t==-1)return -1;
return (t*b+c)/a;
}
ll hh=ny(x,y,1);
2.线性找
假设 k*i+r %p==0
两边同乘 i^-1 r^-1, k*r^-1+i^-1 %p==0
i^-1 %p ==-k*r^-1
i^-1%p==-(p/i)*(p%i)^-1(我不太会证)
于是可以递推求了
A[i]=-(p/i)*A[p%i];
3. ny(i)=i^(mod-2);
中国剩余定理暂过。。
高斯消元:
概率题常用到,就是个板子,但记得不太准。。
num为了处理无解,如果一定有解,num可替成i。
void gaosi()
{
/*已知a[i][j]是第i个方程,第几个变量的参数,
b[i]是第i个方程的常量 */
int im,num=1;
for(int i=1;i<=n;i++,num++)
{
im=i;
for(int j=i+1;j<=n;j++)
if(fabs(a[j][i])>fabs(a[im][i]))
im=j;
if(im!=i)
{
for(int j=1;j<=n;j++)
swap(a[i][j],a[im][j]);
swap(b[i],b[im]);
}
if(!a[num][i]){num--;continue;}
for(int j=num+1;j<=n;j++)
{
if(!a[num][j])continue;
double t=a[j][i]/a[num][i];
for(int k=i+1;k<=n;k++)
a[j][k]-=a[i][k]*t;
b[j]-=b[i]*t;
}
}
for(int i=n;i>=1;i--)
{
for(int j=n;j>i;j--)
b[i]-=a[i][j]*ans[j];
ans[i]=b[i]/a[i][i];
}
}
组合数:
首先说一下线性求法,应付大量询问,打个表。
void init()
{
for(int i=1;i<=2000;i++)
for(int j=1;j<=i;j++)
if(i==1&&(j==1||j==i))
c[i][j]=1;
else
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
然后就是大组合数取模,卢卡斯定理。
int get(int n,int m)
{
if(n<m)return 0;
if(m>n-m)m=n-m;
int s1=1,s2=1;
for(int i=0;i<m;i++)
{
s1=s1*(n-i)%mod;
s2=s2*(i+1)%mod;
}
return (s1*cheng(s2,mod-2))%mod;//cheng()指快速幂
}
int lucas(int n,int m)
{
if(m==0)return 1;
return get(n%mod,m%mod)%mod*lucas(n/mod,m/mod)%mod;
}
3.也可以预处理阶乘,逆元(逆元太大递归求)。
卡特兰数
不知道会不会考,而且我只会求单个值,Catalan(n)=C(2n,n)-C(2n,n-1);
欧拉函数:
1.线性求。
同时能把素数筛出来。
对于素数,phi(i)=i-1;
对于非素数,(i%p!=0) phi(i*p)=phi(i)*phi(p);
(i%p==0) phi(i*p)=phi(i)*p;
void get_phi()
{
phi[1]=1;
for(int i=2;i<=N;i++)
{
if(!mark[i])//是不是素数
{
prime[++tot]=i;
phi[i]=i-1;
}
for(int j=1;j<=tot;j++)
{
if(i*prime[j]>N)break;
mark[i*prime[j]]=1;
if(!(i%prime[j]))
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*phi[j];//利用欧拉函数积性
}
}
}
2,求单个值的
int get_phi(int t)
{
int k=t;
for(int i=2;i*i<=t;i++)
if(t%i==0)
{
k=k-k/i;
while(t%i==0)
t/=i;
}
if(t>1)k=k-k/t;
return k;
}
矩阵乘+快速幂
矩阵乘没啥好说的。。
node cheng(node a,node b)
{
node c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[i][j]+=a[i][k]*b[i][k];
return c;
}
快速幂
int quick(int x,int n)
{
int ans=1;
while(n)
{
if(n&1)ans*=x;
x*=x;
}
return ans;
}
线性筛素数
算了,把它也添上吧。。
int get_prime()
{
for(int i=2;i<N;i++)
{
if(!mark[i])
prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<N;j++)
{
mark[i*prime[j]]=1;
if(!(i%prime[j]))break;
}
}
}
总结就告一段落了。。