[原根 指标 模方程 BSGS] BZOJ 1420 Discrete Root & BZOJ 1319 Sgu261Discrete Roots

求个指标

解个方程就好了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#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 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;
}

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

namespace Math{
	inline abcd EXGCD(ll a,ll b){
		if (a<b) { abcd ret=EXGCD(b,a); return abcd(ret.second,ret.first); }
		if (!b) return abcd(1,0);
		abcd ret=EXGCD(b,a%b);
		return abcd(ret.second,ret.first-a/b*ret.second);
	}
	inline void Solve(ll A,ll B,ll N,vector<ll> &ans){
		A%=N; B%=N;
		if (!A && !B) { for (int i=0;i<N;i++) ans.push_back((ll)i); return; }
		if (!A && B) return;
		if (!B && A) { ans.push_back(0); return; }
		abcd E=EXGCD(A,N);
		ll D=A*E.first+N*E.second,X;
		if (B%D==0)
		{
			X=E.first*(B/D)%N; X=(X%N+N)%N;
			for (int i=0;i<D;i++)
			{
				ans.push_back(X);
				(X+=(N/D))%=N;
			}
		}
	}
}

namespace BSGS{
	struct hashmap{
		#define MOD 1000007
		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 P,K,A,G;
vector<ll> Ans;

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(P); read(K); read(A);
	G=GetRoot(P,P-1);
	A=BSGS::Solve(G,A,P,P-1);
	Math::Solve(K,A,P-1,Ans);
	for (int i=0;i<(signed)Ans.size();i++)
		Ans[i]=Pow(G,Ans[i],P);
	sort(Ans.begin(),Ans.end());
	unique(Ans.begin(),Ans.end());
	printf("%d\n",(signed)Ans.size());
	for (int i=0;i<(signed)Ans.size();i++)
		printf("%lld\n",Ans[i]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值