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

bzoj-2219 數論之神

mod 方程組 borde class pac () 知識點 spa []

題意:

求方程X^A = B(mod 2*K + 1)

X ∈[0, 2K] 內的解的個數;


題解:
一道數論的好題。

涉及知識點大概有:Crt推論。BSGS,EXGCD,原根與指標;

這道題的主要問題在於兩點:

第一點:取模數不是質數,無法利用通常的方式解方程。

可是有中國剩余定理這個東西,定理的推論告訴我們:

一個取模數互質的同余方程組(未必線性),組合起來之後。這個同余方程解的個數為各方程解的個數的乘積

(組合起來的方程的取模數為全部數的積;實際上這裏解的範圍都是屬於[0 ,自己取模數) )

這點十分重要呢,它不僅證明了解的求法。並且假設有隨意一個方程無解,那麽整個就都是無解的。

攻克了這一點之後,就是第二點:怎樣處理一個方程的解的個數。

暫且令當前方程為x^A =B (mod p^d);

由於中國剩余定理要求取模數互質。所以將2*K+1分解質因子作為全部方程;

然而我僅僅會處理p^1的情況怎麽辦啊= =;

分類討論:

p^d|B :這時p^d是B的因子,那麽實際上就是x^A =0 (mod p^d)了;

假設設x=p^k*q。這裏(p,q)=1;

k事實上表示的是x中p因子的個數,那麽在x^A中的個數就是k*A,也就有k*A>=d;

k>=d/A,也就是說k最小為ceil(d/A) (ceil為上取整函數);

由於x的取值範圍是[0,p^d),而x=p^k*q ,顯然d>k。

所以解的個數就是p^d/p^k=p^(d-k)。


gcd(p^d,B)=p^k:這時二者之間有一個公約數;

直觀的想。假設等式兩邊同一時候除一個p^k就解決啦;

可是要保證A|k,要不然的話x^A中約數p的個數就不可能和B的相等(顯然);

當我們成功的把方程p^k*x‘^A= B (mod p^d)

化簡為 x‘^A= B/(p^k) (mod p^(d-k))之後

我們就掛啦!

由於這樣是不正確的,確切的說是x‘的取值範圍變化了;

那麽變化了多少呢?原來的範圍是[0,p^(d-k/A))。而後變成了[0,p^(d-k))。

原因就在於mod值的縮小,可是對於答案的影響和上面一樣:

答案是第二個方程答案的p^(k-k/A)倍。


第二個方程怎麽解? 取指標啊!

取完指標就是線性同余方程了。方程個數就是gcd(A,φ(p^d));

可是有個坑,同余方程可能無解啊。

所以還要大步~小步~BSGS求出一個 以p^d的原根為底,關於B的。對p^d取模的 指標lnB (好TM繞);

然後推斷gcd(A,φ(p^d))| lnB,假設不是因子則無解!

那麽這題就結束了,可喜可賀;


什麽gcd(B,p^d)=1沒討論?事實上不就是上一段怎麽解的事嗎。

什麽復雜度?我但是BZ這題Rank1 (倒數)的人啊;

【反正我咋看咋O(n);

反正我是線性篩搞了個素數表= =

然並卵。似乎復雜度沒有本質改變?


代碼:


#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 140142
using namespace std;
typedef long long ll;
const ll INF=0x7f7f7f7f7f7f7f7f7fll;
struct Hash_Set
{
	ll head[N],next[N],X[N],val[N],tot;
	void clear()
	{
		tot=0;
		memset(head,0,sizeof(head));
		memset(next,0,sizeof(next));
		memset(val,-1,sizeof(val));
		memset(X,0,sizeof(X));
	}
	ll& operator [](ll x)
	{
		ll index=x%N;
		for(ll i=head[index];i;i=next[i])
		{
			if(X[i]==x)
				return val[i];
		}
		next[++tot]=head[index];
		head[index]=tot;
		X[tot]=x;
		return val[tot];
	}
}hash;
ll pri[N],top,a[N],b[N];
bool vis[N];
void init()
{
	for(ll i=2;i<N;i++)
	{
		if(!vis[i])
			pri[++top]=i;
		for(ll j=1;j<=top&&i*pri[j]<N;j++)
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)
				break;
		}
	}
}
ll pow(ll x,ll y,ll mod)
{
	ll ret=1;
	while(y)
	{
		if(y&1)
			ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
ll gcd(ll a,ll b)
{
	ll t=a%b;
	while(t)
	{
		a=b,b=t;
		t=a%b;
	}
	return b;
}
void exgcd(ll a,ll b,ll &x,ll &y,ll &d)
{
	if(!b)
		x=1,y=0,d=a;
	else
	{
		exgcd(b,a%b,y,x,d);
		y-=a/b*x;
	}
}
ll inv(ll X,ll mod)
{
	ll x,y,d;
	exgcd(X,mod,x,y,d);
	return (x%mod+mod)%mod;
}
ll Root(ll x,ll phi)
{
	ll st[N],top=0,temp=phi;
	for(ll i=1,p=2;p*p<=temp;i++,p=pri[i])
	{
		if(temp%p==0)
		{
			st[++top]=phi/p;
			while(temp%p==0)
				temp/=p;
		}
	}
	if(temp!=1)
		st[++top]=phi/temp;
	for(ll i=1,j;i<=phi;i++)
	{
		for(j=1;j<=top;j++)
		{
			if(pow(i,st[j],x)==1)
				break;
		}
		if(j>top)
			return i;
	}
}
ll BSGS(ll A,ll B,ll C)
{
	hash.clear();
	ll bk=ceil(sqrt(C*1.0)),i,k,D,temp;
	for(i=0,D=1;i<bk;i++,D=D*A%C)
	{
		if(hash[D]==-1)
			hash[D]=i;
	}
	temp=inv(D,C);
	for(i=0,k=B;i<=bk;i++,k=k*temp%C)
	{
		if(hash[k]!=-1)
			return i*bk+hash[k];
	}
	return 0;
}
ll slove(ll A,ll B,ll C)
{
	ll i,j,k,p,mod,lnB,g,d,cnt,ans;
	for(i=1,p=2,ans=1;p*p<=C;i++,p=pri[i])
	{
		if(C%p==0)
		{
			mod=1,cnt=0;
			while(C%p==0)
				C/=p,mod*=p,cnt++;
			if(B%mod==0)
			{
				d=pow(p,cnt-ceil(cnt*1.0/A),INF);
			}
			else
			{
				k=0;
				while(B%p==0)
					k++,B/=p;
				if(k%A)	d=0;
				else
				{
					g=Root(mod,mod-mod/p);
					lnB=BSGS(g,B,mod);
					d=gcd(A,mod-mod/p);
					if(lnB%d)	d=0;
					d*=pow(p,k-k/A,INF);
				}
			}
			ans*=d;
		}
	}
	if(C!=1)
	{
			mod=C,p=C,cnt=1;
			if(B%mod==0)
			{
				d=pow(p,cnt-ceil(cnt*1.0/A),INF);
			}
			else
			{
				k=0;
				while(B%p==0)
					k++,B/=p;
				if(k%A)	d=0;
				else
				{
					g=Root(mod,mod-mod/p);
					lnB=BSGS(g,B,mod);
					d=gcd(A,mod-mod/p);
					if(lnB%d)	d=0;
					d*=pow(p,k-k/A,INF);
				}
			}
			ans*=d;
	}
	return ans;
}
int main()
{
	init();
	ll c,T,A,B,C;
	scanf("%lld",&T);
	for(c=1;c<=T;c++)
	{
		scanf("%lld%lld%lld",&A,&B,&C);
		printf("%lld\n",slove(A,B,C<<1|1));
	}
	return 0;
}



bzoj-2219 數論之神