[学习笔记]数论基础篇2

原根

已知当 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1时, a ϕ ( b ) % b = 1 a^{\phi(b)}\%b=1 aϕ(b)%b=1
定义在模 b b b意义下, a a a的阶为 d d d,且 a d % b = 1 a^d\%b=1 ad%b=1
如果 a a a的阶为 ϕ ( b ) \phi(b) ϕ(b),则 a a a就为 b b b的原根

大步小步算法(bsgs)

b s g s bsgs bsgs算法用于求离散对数,即已知 a , b , p a,b,p a,b,p求满足 a x ≡ b   ( m o d   p ) a^x\equiv b\ (mod\ p) axb (mod p) x x x,其中 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1
由欧拉定理可知 a ϕ ( p ) % p = 1 a^{\phi(p)}\%p=1 aϕ(p)%p=1,所以我们可以通过暴力枚举 x x x来求是否满足条件,时间复杂度为 O ( p ) O(p) O(p)
p p p很大时,这个方法就直接被干掉了,于是有了 b s g s bsgs bsgs算法
m = ⌈   p ⌉ m=\lceil\sqrt\ p\rceil m=  p,设 r = x % m r=x\%m r=x%m x = k ∗ m + r x=k*m+r x=km+r 其中 0 < = k < m   0 < = r < m 0<=k<m\ 0<=r<m 0<=k<m 0<=r<m
我们便有了 a k ∗ m + r ≡ b   ( m o d   p ) a^{k*m+r}\equiv b\ (mod\ p) akm+rb (mod p)
得到 a k ∗ m ≡ b ∗ a − r   ( m o d   p ) a^{k*m}\equiv b*a^{-r}\ (mod\ p) akmbar (mod p)
那么我们就可以处理出 b ∗ a − r % p b*a^{-r}\%p bar%p的值,存进 m a p map map里面
在枚举 k k k,求到 a k ∗ m % p a^{k*m}\%p akm%p是否存在,存在则就可以输出 x = k ∗ m + r x=k*m+r x=km+r,如果都没有,则无解
a k ∗ m ≡ b ∗ a − r a^{k*m}\equiv b*a^{-r} akmbar中我们涉及到了要处理逆元,但是必须是要 g c d ( a r , p ) = 1 gcd(a^{r},p)=1 gcd(ar,p)=1,但是一些丧心病狂的出题人就会卡你,所以我们设 x = k ∗ m − r x=k*m-r x=kmr 其中 0 < k < = m   0 < r < = m 0<k<=m\ 0<r<=m 0<k<=m 0<r<=m
上面的式子就可以变成 a k ∗ m ≡ b ∗ a r   ( m o d   p ) a^{k*m}\equiv b*a^{r}\ (mod \ p) akmbar (mod p)
处理便一样,记得要特判掉 b = 0 b=0 b=0的情况
代码是网上的一个巨佬的,因为找不到自己的了

LL m=ceil(sqrt(c));// 注意要向上取整
        mp.clear();
        if(a%c==0)
        {
        printf("no solution\n");
        continue;
        }
        // 费马小定理的有解条件
        LL ans;//储存每一次枚举的结果 b* a^j
        for(LL j=0;j<=m;j++)  // a^(i*m) = b * a^j
        {
            if(j==0)
            {
                ans=b%c;
                mp[ans]=j;// 处理 a^0 = 1
                continue;
            }
            ans=(ans*a)%c;// a^j
            mp[ans]=j;// 储存每一次枚举的结果
        }
        LL t=fastpow(a,m,c);
        ans=1;//a ^(i*m)
        LL flag=0;
        for(LL i=1;i<=m;i++)
        {
            ans=(ans*t)%c;
            if(mp[ans])
            {
                LL out=i*m-mp[ans];// x= i*m-j
                printf("%lld\n",(out%c+c)%c);
                flag=1;
                break;
            }

        }
        if(!flag)
        printf("no solution\n");

扩展大步小步算法(exbsgs)

扩展大步小步也是解决 已知 a , b , p a,b,p a,b,p求满足 a x ≡ b   ( m o d   p ) a^x\equiv b\ (mod\ p) axb (mod p) x x x这一类问题的,只是当 a , p a,p a,p不互质的情况,上面的方法解决不了了。
根据给出的式子我们可以得到 a x + k p = b a^x+kp=b ax+kp=b
因为 a , p a,p a,p不互质,我们设 d = g c d ( a , p ) d=gcd(a,p) d=gcd(a,p)
上式同除 d d d,得到 a x − 1 ∗ a / d + k p / d = b / d a^{x-1}*a/d+kp/d=b/d ax1a/d+kp/d=b/d
b / d ≠ 0 b/d\ne0 b/d=0时,这个方程便无解
a , p ′ a,p' a,p仍然不互质,继续除去 g c d ( a , p ′ ) gcd(a,p') gcd(a,p)
当他们互质的时候,我们便有了 a x − c n t ≡ b / a ′   ( m o d   p ′ ) a^{x-cnt}\equiv b/a'\ (mod\ p') axcntb/a (mod p)
这里的 c n t cnt cnt表示总共取了多少个 a a a出来取 g c d gcd gcd, a ′ a' a表示这些取出来的 a a a除了 g c d gcd gcd后的乘积
这里 a , p ′ a,p' a,p又互质了,便回到了 b s g s bsgs bsgs,为了避免逆元,我们便把左边的初始值设为 a ′ a' a

int qkpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)
            ans=1ll*ans*a%p;
        b>>=1;
        a=1ll*a*a%p;
    }
    return ans;
}
map<LL,int> mp;
void exbsgs(int x,int y){
    if(y==1){
        printf("0\n");
        return;
    }
    int d=__gcd(x,p),k=1,cnt=0;
    while(d!=1){
        if(y%d!=0){
            puts("No Solution");
            return;
        }
        cnt++;y/=d,p/=d;
        k=1ll*k*x/d%p;
        if(y==k){
            writeint(cnt);
            puts("");
            return;
        }
        d=__gcd(x,p);
    }
    int s=y;
    mp.clear();
    int m=sqrt(p-1)+1;
    for(int i=0;i<=m;i++){
        mp[s]=i;
        s=1ll*s*x%p;
    }
    s=k,k=qkpow(x,m);
    for(int i=1;i<=m;i++){
        s=1ll*s*k%p;
        if(mp.count(s)){
            writeint(i*m-mp[s]+cnt);
            puts("");
            return;
        }
    }
    puts("No Solution");
}

miller_rabbin算法

这是一个用来判断素数的方法,利用了随机算法可以在很快的时间内判断一个数是否是质数。
根据费马小定理,如果 p p p是一个质数,则有 a p − 1 % p = 1   a < p a^{p-1}\%p=1\ a<p ap1%p=1 a<p
但是反过来就不一样了,因为有一类称为迈克尔数也满足这个式子,但这个数不一定是质数
我们令 p − 1 = 2 k ∗ r p-1=2^k*r p1=2kr a p − 1 = a r 2 k a^{p-1}=a^{r^{2k}} ap1=ar2k
我们初始值设为 a r a^r ar,然后不断平方
如果第一次出现模 p p p的值为 1 1 1,那么检测上一次的值是否为 − 1 -1 1 ,如果是,则没有毛病;否则可以断定不是质数。
y 2 % p = 1 y^2\%p=1 y2%p=1
y 2 − 1 % p = 0 y^2-1\%p=0 y21%p=0
( y − 1 ) ∗ ( y + 1 ) % p = 0 (y-1)*(y+1)\%p=0 (y1)(y+1)%p=0
因为 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1,所以 g c d ( y , p ) = 1 gcd(y,p)=1 gcd(y,p)=1
所以要么 ( y − 1 ) % p = 0 (y-1)\%p=0 (y1)%p=0
要么 ( y + 1 ) % p = 0 (y+1)\%p=0 (y+1)%p=0
y = 1 y=1 y=1或者 y = p − 1 y=p-1 y=p1(即在在模 p p p的意义下为 − 1 -1 1)

#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
#define int long long
int read()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n;
int ksc(int a,int b)
{
	int res=0;
	while(b)
	{
		if(b&1) res=res+a;
		a=a+a;
		if(res>=n) res-=n;
		if(a>=n) a-=n;
		b>>=1;
	}
	return res;
}
int qkpow(int a,int b)
{
	int r=1;
	while(b>0)
	{
		if(b&1) r=ksc(r,a);
		a=ksc(a,a);
		b>>=1;
	}
	return r;
}
int miller()
{
	int k=n-1,t=0;
	while(k%2==0)
	{
		t++;
		k/=2;
	}
	for(int i=0;i<=10;i++)
	{
		int a=rand()%(n-1)+1,ls,np=0;
		a=qkpow(a,k);ls=a;
		if(a==1) continue;
		for(int j=1;j<=t;j++)
		{
			a=ksc(a,a);
			if(a==1)
			{
				if(ls!=n-1) np=1;
				break;
			}
			ls=a;
		}
		if(np || a!=1) return 0;
	}
	return 1;
}
signed main()
{
	srand(time(0));
	while(~scanf("%I64d",&n))
	{
		if(n&1==0)
		{
			puts("It is not a prime number.");
			continue;
		}
		if(miller()) puts("It is a prime number.");
		else puts("It is not a prime number.");
	}
}

高斯消元

int gauss(){
	int row=1,col=1;
	for(;row<=n&&col<=m;row++,col++){
		int cur=row;
		for(int i=row+1;i<=n;i++){
			if(Fabs(a[i][col])>Fabs(a[cur][col])){
				cur=i;
			}
		}
		if(cur!=row){
			for(int i=col;i<=m+1;i++) 
				swap(a[cur][i],a[row][i]);
		}
		if(a[row][col]==0){
			row--;
			continue;
		}
		for(int i=row+1;i<=n;i++){
			if(a[i][col]!=0){
				LL LCM=lcm(a[i][col],a[row][col]);
				LL tmpa=LCM/a[i][col];
				LL tmpb=LCM/a[row][col];
				for(int j=col;j<=m+1;j++) 
					a[i][j]=(a[i][j]*tmpa-a[row][j]*tmpb)%mo;
			}
		}
	}
	for(int i=row;i<=n;i++) 
		if(a[i][col]!=0) 
			return -1;
	if(row<=m) return m-row+1;
	for(int i=n;i>=1;i--){
		LL tmp=a[i][m+1];
		for(int j=i+1;j<=m;j++) 
			tmp=(tmp-x[j]*a[i][j])%mo;
		x[i]=tmp*inv(a[i][i])%mo;
	}
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
const double eps = 1e-7;
int readint(){
	int x=0,f=1;char s=getchar();
	#define sc (s=getchar())
	while(s<'0'||s>'9'){
		if(s=='-')
			f=-1;
		sc;
	}
	while(s>='0'&&s<='9'){
		x=(x<<3)+(x<<1)+(s^48);
		sc;
	}
	#undef sc
	return x*f;
} 
double a[maxn][maxn];
double ans[maxn];
int main (){
	int n=readint();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n+1;j++)
			scanf("%lf",&a[i][j]);
	} 
	for(int i=1;i<=n;i++){
		int now=i;
		for(int j=i+1;j<=n;j++){
			if(fabs(a[j][i])>fabs(a[now][i]))
				now=j;
		}
		if(fabs(a[now][i])<eps){
			puts("No Solution");
			return 0;
		}
		if(i!=now)
			swap(a[i],a[now]);
		for(int j=i+1;j<=n;j++){
			double temp=a[j][i]/a[i][i];
			for(int k=i;k<=n+1;k++)
				a[j][k]-=a[i][k]*temp;
		}
	}
	ans[n]=a[n][n+1]/a[n][n];
	for(int i=n-1;i>=1;i--){
		for(int j=1;j<=i;j++){
			a[j][n+1]-=ans[i+1]*a[j][i+1];
		}
		ans[i]=a[i][n+1]/a[i][i];
	}
	for(int i=1;i<=n;i++){
		printf("%.2f\n",ans[i]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值