[置顶] 数学的坑,一点点来填

   数学这个坑实在太大了,说白了是我太弱了 

   联赛考的:同余(解方程+逆元),欧拉函数,筛素数(这个过了),组合数,矩阵乘+快速幂,高斯消元

   一点点把板子都总结一下。

   同余方程:

   首先是解线性同余的板子。

    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;
		}
	}
}

  总结就告一段落了。。

posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(151)  评论(0编辑  收藏  举报