BZOJ 2219 数论之神 数论

42 篇文章 0 订阅

题目大意:求在[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
	}
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值