原根

本文介绍了原根的概念及其在数论中的应用,并提供了一种寻找最小原根的方法。此外,还探讨了原根在NTT(Number Theoretic Transform)中的作用,给出NTT的实现模板代码。

[大佬blog](https://www.cnblogs.com/cjoieryl/p/8438756.html)

令Ord(a,b)= 最小的使 a ^ n % b == 1 的n

那么若a是b的原根,则Ord(a,b)=phi(b)

最小原根一般ha以枚举

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#define maxn 1000005
using namespace std;

int n;

int pr[maxn],cnt_pr;
bool vis[maxn];
void Euler_sieve(int lim)
{
	for(int i=2,j;i<=lim;i++)
	{
		if(!vis[i]){ pr[cnt_pr++]=i; }
		for(j=0;j<cnt_pr && pr[j]*i<=lim;j++)
		{
            vis[pr[j]*i]=1;
            if(i%pr[j]==0) break;
		}
	}
}

int pow(int base,int deg,int p)
{
	int ret=1;
	for(;deg;deg>>=1,base=1ll*base*base%p) if(deg&1) ret=1ll*ret*base%p;
	return ret;
}

int fac[maxn];
bool check(int num)
{
	for(int i=1;i<=fac[0];i++)
		if(pow(num,(n-1)/fac[i],n)==1)
			return 0;
	return 1;
}


int main()
{
	scanf("%d",&n);
	Euler_sieve((int)(sqrt(n)+1));
	for(int i=0,sum=n-1;i<cnt_pr && pr[i]*pr[i]<=sum;i++)
		if(sum%pr[i]==0)
		{
			fac[++fac[0]]=pr[i];
			while(sum%pr[i]==0)
                sum/=pr[i];
		}

	for(int i=2;i<n;i++)
		if(check(i))
		{
			printf("%d\n",i);
			break;
		}
}

 

 

原根还可以用于NTT,性质类似单位根。

NTT模板:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define maxn 4000005
using namespace std;

int n,m,len;
int P=998244353,G=3,invG;
int wn[2][30];

int pow(int base,int deg,int P)
{
	int ret=1;
	for(;deg;deg>>=1,base=1ll*base*base%P) if(deg&1) ret=1ll*ret*base%P;
	return ret;
}

void Prework()
{
	invG=pow(G,P-2,P);
	for(int i=1;i<=20;i++) wn[1][i]=pow(G,(P-1)/(1<<i),P),wn[0][i]=pow(invG,(P-1)/(1<<i),P);
}

int A[maxn],B[maxn];

void NTT(int *A,int n,int typ)
{
	for(int i=0,j=0,k;i<n;i++)
	{
		if(i<j) swap(A[i],A[j]);
		for(k=n>>1;k;k>>=1) if((j^=k)>=k) break;
	}

	for(int i=1,j,k,len,w,x,y;(1<<i)<=n;i++)
	{
		len=1<<(i-1);
		for(j=0;j<n;j+=1<<i)
		{
			w=1;
			for(k=0;k<len;k++,w=1ll*w*wn[typ][i]%P)
			{
				x=A[j+k],y=1ll*A[j+k+len]*w%P;
				A[j+k]=(x+y)%P;
				A[j+k+len]=(x-y)%P;
			}
		}
	}

	if(typ==0)
		 for(int i=0,inv=pow(n,P-2,P);i<n;i++)
			A[i]=1ll*A[i]*inv%P;
}

int main()
{
	Prework();
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++) scanf("%d",&A[i]);
	for(int i=0;i<=m;i++) scanf("%d",&B[i]);
	for(len=1;len<=(n+m);len<<=1);
	NTT(A,len,1);
	NTT(B,len,1);
	for(int i=0;i<=len;i++) A[i]=1ll*A[i]*B[i]%P;
	NTT(A,len,0);
	for(int i=0;i<n+m;i++) printf("%d ",(A[i]+P)%P);
	printf("%d\n",(A[n+m]+P)%P);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值