[阶 原根 指标]BZOJ 2219 数论之神

数论好题,总算把数论这一块遗漏的知识补齐了

题解传送:


http://blog.csdn.net/regina8023/article/details/44863519


http://blog.csdn.net/popoqqq/article/details/41595187


1.【阶】 
满足 ax1(modp)  的最小的 x a 关于 p 的阶。 
记作 δ(a)=x

2.【原根】 
δ(g)=φ(p) ,则称 g p 的原根。

(1)只有 1,2,4,pk,2pk p 是奇素数)有原根。

(2) p 的原根个数为 φ(φ(p))  
(证明见这里

(3) p>1 , φ(p) 所有不同的因数为 p1,p2,,pk (g,m)=1 ,则 g 是模 p 的原根的充要条件是: gpi1(modp) 对于所有的 pi 都不成立 
(这也是原根的求法)

3.【指标】 
gra(modp) 成立,则称 r 是以 g 为底的 a 对模 m 的一个指标。 
记作 r=inda

(1) ab(modp)indaindb(modφ(p))

(2) ind(ab)inda+indb(modφ(p))

(3) ind(an)ninda(modφ(p))

(4)指标的求法: 
先求出 p 的原根 g ,然后用BSGS求出 gab(modp) 中的 a  
(BSGS详见这里


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(ll &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int write(ll x,char c)
{
	if (x==0) return putchar('0'),putchar(c),0;
	if (x<0) putchar('-'),x=-x;
	char s[50]={0},len=0;
	while (x) s[++len]=x%10+'0',x/=10;
	for (int i=len;i;i--) putchar(s[i]); putchar(c);
}

inline ll Pow(ll a,ll b,ll p)
{
	ll ret=1;
	for (;b;(a*=a)%=p,b>>=1)
		if (b&1)
			(ret*=a)%=p;
	return ret;
}

inline abcd EXGCD(ll a,ll b)
{
	abcd ret;
	if (a<b) {	ret=EXGCD(b,a); return abcd(ret.second,ret.first); }
	if (!b) return abcd(1,0);
	ret=EXGCD(b,a%b);
	return abcd(ret.second,ret.first-a/b*ret.second);
}

namespace BSGS{
	struct hashmap{
		#define MOD 10007
		ll num;
		ll key[1000005],value[1000005],next[1000005];
		ll head[MOD];
		inline void insert(ll k,ll v)
		{
			ll ad=k%MOD;
			key[++num]=k; value[num]=v; next[num]=head[ad];
			head[ad]=num;
		}
		inline ll operator[](ll k)
		{
			ll ad=k%MOD;
			for (int p=head[ad];p;p=next[p])
				if (key[p]==k)
					return value[p];
			return -1;
		}
		inline void clear()
		{
			cl(head); num=0;
		}
	}M;
	inline ll Solve(ll A,ll B,ll P,ll phi)
	{
		M.clear();
		A%=P;
		if (!A && !B) return 1;
		if (!A) return -1;
		ll m=sqrt((double)P)+1,tmp=1;
		M.insert(1,0);
		for (int i=1;i<m;i++)
		{
			(tmp*=A)%=P;
			if (M[tmp]==-1) 
				M.insert(tmp,i);
		}
		ll inv=1,T=Pow(A,phi-m,P);
		for (int k=0;k<m;k++)
		{
			ll i=M[B*inv%P];
			if (i!=-1)
				return k*m+i;
			(inv*=T)%=P;
		}
		return -1;
	}
}

ll f[1000005];

inline ll GetRoot(ll p,ll phi)
{
	int c=0;
	for (int i=2;i*i<=phi;i++)
		if (phi%i==0)
			f[++c]=i,f[++c]=phi/i;
	for (int g=2;g<p;g++)
	{
		int j;
		for (j=1;j<=c;j++)
			if (Pow(g,f[j],p)==1) 
				break;
		if (j==c+1) return g;
	}
	return 0;
}

inline ll Equ(ll a,ll b,ll p)
{
	a%=p; b%=p;
	abcd E=EXGCD(p,a);
	ll d=p*E.first+a*E.second;
	if (b%d==0)
		return d;
	else
		return 0;
}

ll A,B,P;
ll ans,cnt;

struct data{
	ll p,c,p_c;
};

data a[1000005];
int num;

inline void Machine(ll P)
{
	num=0;
	for (int i=2;P!=1 && i<=sqrt(P)+0.50;i++)
		if (P%i==0)
		{
			a[++num].p=i;
			a[num].p_c=1;
			a[num].c=0;
			while (P%i==0)
				P/=i,a[num].c++,a[num].p_c*=i;
		}
	if (P!=1)
		a[++num].p=P,a[num].c=1,a[num].p_c=P;
}

inline ll Cal(ll A,ll B,ll k)
{
	ll phi=a[k].p_c-a[k].p_c/a[k].p;
	ll g=GetRoot(a[k].p_c,phi);
	ll ind=BSGS::Solve(g,B,a[k].p_c,phi);
	ll ret=Equ(A,ind,phi);
	return ret*Pow(a[k].p,cnt-cnt/A,1LL<<60);
}

int main()
{
	ll Q,k,tmp;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(Q);
	while (Q--)
	{
		read(A); read(B); read(k); P=2*k+1; B%=P;
		Machine(P);
		ans=1;
		for (int i=1;i<=num;i++)
		{
			if (!ans) break;
			if (B%a[i].p_c==0)
			{
				tmp=Pow(a[i].p,a[i].c-(a[i].c-1)/A-1,1LL<<60);
			}
			else
			{
				ll b=B;
				cnt=0;
				while (b%a[i].p==0)
				{
					cnt++; b/=a[i].p;
					a[i].p_c/=a[i].p;
					a[i].c--;
				}
				if (cnt%A)
					tmp=0;
				else
					tmp=Cal(A,b,i);
			}
			ans*=tmp;
		}
		write(ans,'\n');
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值