BZOJ 2219 数论之神

在ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀! 一天他在群里面问了一个神题:对于给定的 3 3 3个非负整数 A , B , K A,B,K A,B,K 求出满足
( 1 ) X A = B ( m o d 2 ∗ K + 1 ) (1) X^A= B(mod 2*K + 1) (1)XA=B(mod2K+1)
( 2 ) X (2) X (2)X在范围 [ 0 , 2 K ] [0, 2K] [0,2K]
X X X的个数!

这个题解明明超详细却打错了一两个公式
有点数论大礼包的感觉。

#include<bits/stdc++.h>
using namespace std;

map<int,int>mp;
int p[20],c[20];
int gcd(int a,int b){ return !b ? a : gcd(b,a%b); }
int Pow(int base,int k){
	int ret = 1;
	for(;k;k>>=1,base=base*base)
		if(k&1)
			ret=ret*base;
	return ret;
}
int Pow(int base,int k,int p){
	int ret = 1;
	for(;k;k>>=1,base=1ll*base*base%p)
		if(k&1)
			ret=1ll*ret*base%p;
	return ret;
}
int Getg(int P,int phi){
	static int p[20];
	p[0] = 0;
	int u = phi;
	for(int i=2;i*i<=u;i++)
		if(u%i==0){
			p[++p[0]] = phi / i;
			for(;u%i==0;u/=i);
		}
	if(u>1) p[++p[0]] = phi/u;
	for(int r=2;;r++) if(gcd(r,P)==1){
		bool flg = 0;
		for(int i=1;i<=p[0];i++)
			if(Pow(r,p[i],P) == 1)
			{ flg = 1; break; }
		if(!flg) return r;
	}
}

int main(){
	int T;
	for(scanf("%d",&T);T--;){
		p[0] = 0;
		int A,B,C;
		scanf("%d%d%d",&A,&B,&C);C=C*2+1;
		for(int i=2;i*i<=C;i++)	
			if(C%i==0){
				p[++p[0]] = i , c[p[0]] = 0;
				for(;C%i==0;C/=i,c[p[0]]++);
			}
		if(C>1) p[++p[0]]=C,c[p[0]]=1;
		int ans = 1;
		for(int i=1;i<=p[0];i++){
			int t = gcd(B,Pow(p[i],c[i])) , ct = 0;
			if(t == Pow(p[i],c[i])){ ans = 1ll * ans * Pow(p[i],c[i]-ceil(c[i]*1.0/A)); continue; }
			for(int u=t;u>1;u/=p[i],ct++);
			if(ct % A){ ans = 0; break; }
			int P = Pow(p[i],c[i]-ct) , b = (B / t) % P , g = Getg(P,P/p[i]*(p[i]-1)) , c = 1 , d = 1 , M = ceil(sqrt(P/p[i]*(p[i]-1)));
			mp.clear();
			for(int j=1;j<=M;j++) c = 1ll * c * g % P,mp[1ll * c * b % P]=j;
			for(int j=1;j<=M+1;j++){
				d = 1ll * d * c % P;
				if(mp.count(d)){ b=j*M-mp[d];break; }
			}
			int e = gcd(A,P/p[i]*(p[i]-1));
			if(b % e){ ans=0;break; }
			ans = ans * e * Pow(p[i],ct-ct/A);
		}
		printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值