1. 程式人生 > >BZOJ 2219 數論之神 數論

BZOJ 2219 數論之神 數論

題目大意:求在[0,p)範圍內的解的個數

鏼爺的題解:http://jcvb.is-programmer.com/posts/42036

我只是來粘程式碼的QAQ

指標啥的原根啥的中國剩餘定理啥的真的完全不知道QAQ

UPD:時隔多年 在這道題被Hack過一次之後 我終於重新AC了這道題- -

大致說下做法吧


感覺說的這麼詳細不利於深刻理解- -

算了看在這題被Hack得這麼慘的份上還是全講出來吧- -

感謝鏼爺的題解,感謝Mato的資料,感謝wyfcyx喪心病狂地把這組資料加到了OJ上(笑

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF static_cast<ll>(1e15)
#define M 100100
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;
namespace Hash_Set{
	ll hash_table[M],val[M],tim[M],T;
	inline void Clear()
	{
		++T;
	}
	ll Hash(ll x,ll v)
	{
		ll i;
		for(i=x%M;tim[i]==T;i++,i%=M)
			if(hash_table[i]==x)
				return val[i];
		tim[i]=T;hash_table[i]=x;
		return val[i]=v;
	}
}
ll Quick_Power(ll x,ll y,ll p)
{
	ll re=1;
	while(y)
	{
		if(y&1) re*=x,re%=p;
		x*=x,x%=p;
		y>>=1;
	}
	return re;
}
ll Get_Primitive_Root(ll p,ll phi_p)
{
	static ll factors[500];
	int i,j,tot=0;
	for(i=2;i*i<phi_p;i++)
		if(phi_p%i==0)
			factors[++tot]=i,factors[++tot]=phi_p/i;
	if(i*i==phi_p) factors[++tot]=i;
	for(i=2;i<p;i++)
	{
		for(j=1;j<=tot;j++)
			if(Quick_Power(i,factors[j],p)==1)
				break;
		if(j==tot+1)
			return i;
	}
	return 0;
}
ll GCD(ll x,ll y)
{
	return y?GCD(y,x%y):x;
}
abcd EXGCD(ll x,ll y)
{
	if(!y) return abcd(1,0);
	abcd temp=EXGCD(y,x%y);
	return abcd(temp.second,temp.first-x/y*temp.second);
}
ll Baby_Step_Giant_Step(ll A,ll B,ll C)
{
	ll i,A_m,D,m=static_cast<int>(ceil(sqrt(C))+1.0000001);
	Hash_Set::Clear();
	for(i=0,A_m=1;i<m;i++,A_m*=A,A_m%=C)
		Hash_Set::Hash(A_m,i);
	for(i=0,D=1;i<=m;i++,D*=A_m,D%=C)
	{
		abcd temp=EXGCD(D,C);
		ll x=(temp.first*B%C+C)%C;
		ll re=Hash_Set::Hash(x,-1);
		if(~re) return i*m+re;
	}
	return 0;
}
ll Solve(ll a,ll b,ll p,ll d)
{
	ll p_d=Quick_Power(p,d,INF);
	b%=p_d;
	if(!b) return Quick_Power(p,d-( (d-1)/a+1 ),INF);
	ll temp=0;
	while(b%p==0)
		b/=p,temp++;
	if(temp%a) return 0;
	d-=temp;
	ll phi=p_d-p_d/p,g=Get_Primitive_Root(p_d,phi);
	ll ind=Baby_Step_Giant_Step(g,b,p_d);
	ll re=GCD(a,phi);
	if(ind%re) return 0;
	return re*Quick_Power(p,temp-temp/a,INF);
}
int main()
{
	ll T,i;
	ll a,b,k,ans;
	
	for(cin>>T;T;T--)
	{
		#ifdef ONLINE_JUDGE
			scanf("%lld%lld%lld",&a,&b,&k);
		#else
			scanf("%I64d%I64d%I64d",&a,&b,&k);
		#endif
	
		k=k<<1|1;ans=1;
		for(i=2; i*i<=k && ans ;i++)
			if(k%i==0)
			{
				ll temp=0;
				while(k%i==0)
					k/=i,++temp;
				ans*=Solve(a,b,i,temp);
			}
		if( ans && k^1 ) ans*=Solve(a,b,k,1);

		#ifdef ONLINE_JUDGE
			printf("%lld\n",ans);
		#else
			printf("%I64d\n",ans);
		#endif
	}
}