洛谷:P5668 【模板】N 次剩余

*转载于该题题解

#include<stdio.h>
#include<vector>
#include<ext/pb_ds/assoc_container.hpp>
typedef long long ll;
bool f;
int lp,le,e[2000001];
ll n,m,k,p[21],pw[21],c[21];
std::vector<ll>r[21];
__gnu_pbds::gp_hash_table<ll,ll>h;
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
ll Pow(ll a,ll b,ll m)
{
	ll s=1;
	for(a%=m;b;a=a*a%m,b>>=1)
		if(b&1)
			s=s*a%m;
	return s;
}
ll BSGS(ll a,ll b,ll m)
{
	a%=m,b%=m,h.clear();
	if(b==1)
		return 0;
	if(!a&&b)
		return -1;
	ll s=sqrt(m)+1,aa=1;
	for(ll i=0;i<s;i++)
		h[b*aa%m]=i,aa=aa*a%m;
	for(ll i=1,j=aa;i<=s;i++,j=j*aa%m)
	{
		int x=h[j];
		if(x||j==b)
			return i*s-x;
	}
	return -1;
}
ll exgcd(ll a,ll b,ll&x,ll&y)
{
	if(!b)
		return x=1,y=0,a;
	int g=exgcd(b,a%b,y,x);
	return y-=a/b*x,g;
}
bool DiscreteRoots(ll z)
{
	if(k%pw[z])
	{
		ll kp=k%pw[z],pk=1,mk=0;
		while(kp%p[z]==0)
			kp/=p[z],pk*=p[z],mk++;
		if(mk%n)
			return 1;
		ll pwk=pw[z]/pk,h=pwk/p[z]*(p[z]-1),g,le=0,e[21];
		if(Pow(kp,h/gcd(n,h),pwk)!=1)
			return 1;
		for(ll i=2;i*i<=h;i++)
			if(h%i==0)
			{
				while(h%i==0)
					h/=i;
				e[le++]=i;
			}
		if(h>1)
			e[le++]=h;
		for(g=1;;g++)
		{
			bool f=1;
			for(int i=0;i<le&&f;i++)
				if(Pow(g,pwk/p[z]*(p[z]-1)/e[i],pwk)==1) 
					f=0;
			if(f)
				break;
		}
		ll x=BSGS(g,kp,pwk),ka,kb,y=exgcd(n,pwk/p[z]*(p[z]-1),ka,kb);
		if(x%y)
			return 1;
		h=pwk/p[z]*(p[z]-1)/y,kb=Pow(p[z],mk/n,pw[z]),r[z].resize(y*(pk/kb)),r[z][0]=Pow(g,(ka*(x/y)%h+h)%h,pwk),ka=kb,kb=Pow(g,h,pwk);
		for(ll i=1;i<y;i++)
			r[z][i]=r[z][i-1]*kb%pwk;
		for(ll i=y;i<y*(pk/ka);i++)
			r[z][i]=(r[z][i-y]+pwk)%(pw[z]/ka);
		for(ll i=0;i<y*(pk/ka);i++)
			r[z][i]=r[z][i]*ka;
	}
	else
	{
		ll x=0,y=1,o=Pow(p[z],n,pw[z]);
		while(y)
			x++,y=y*o%pw[z];
		r[z].resize(o=pw[z]/(y=Pow(p[z],x,pw[z]+1)));
		for(ll i=0;i<o;i++)
			r[z][i]=i*y;
	}
	return 0;
}
void dfs(ll st,ll x)
{
	if(st==lp)
	{
		e[le++]=x;
		return;
	}
	for(ll i:r[st])
		dfs(st+1,(x+i*c[st])%m);
	return;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lld%lld%lld",&n,&m,&k),f=1,lp=le=0;
		if(n==1)
		{
			printf("1\n%lld\n",k);
			continue;
		}
		if(!(m&7))
		{
			ll mp=3;
			p[0]=2,pw[0]=8,m>>=3;
			while(!(m&1))
				m>>=1,pw[0]<<=1,mp++;
			if(k&pw[0]-1)
			{
				ll k2=k&pw[0]-1,r2=0;
				while(!(k2&1))
					k2>>=1,r2++;
				if(r2%n)
				{
					puts("0");
					continue;
				}
				if(pw[0]>>r2>4)
				{
					ll w_1=0,w5=BSGS(5,k2,pw[0]>>r2);
					if(!~w5)
						w_1=1,w5=BSGS(5,(pw[0]>>r2)-k2,pw[0]>>r2);
					if(n&1)
					{
						ll x,y,g=exgcd(n,pw[0]>>r2+2,x,y);
						if(w5%g)
						{
							puts("0");
							continue;
						}
						w5/=g,x=x*w5&(pw[0]>>r2+2)/g-1,y=Pow(5,(pw[0]>>r2+2)/g,pw[0]>>r2),r[0].resize(g),r[0][0]=w_1?(pw[0]>>r2)-Pow(5,x,pw[0]>>r2):Pow(5,x,pw[0]>>r2);
						for(ll i=1;i<g;i++)
							r[0][i]=r[0][i-1]*y&(pw[0]>>r2)-1;
					}
					else if(w_1)
					{
						puts("0");
						continue;
					}
					else
					{
						ll x,y,g=exgcd(n,pw[0]>>r2+2,x,y);
						if(w5%g)
						{
							puts("0");
							continue;
						}
						w5/=g,x=x*w5&(pw[0]>>r2+2)/g-1,y=Pow(5,(pw[0]>>r2+2)/g,pw[0]>>r2),r[0].resize(g<<1),r[0][g]=(pw[0]>>r2)-(r[0][0]=Pow(5,x,pw[0]>>r2));
						for(ll i=1;i<g;i++)
							r[0][i]=r[0][i-1]*y&(pw[0]>>r2)-1,r[0][i+g]=r[0][i+g-1]*y&(pw[0]>>r2)-1;
					}
				}
				else
					for(ll i=0;i<pw[0]>>r2;i++)
						if(Pow(i,n,pw[0]>>r2)==k&(pw[0]>>r2)-1)
							r[0].emplace_back(i);
				ll s=r[0].size();
				r[0].resize(s<<r2-r2/n);
				for(ll i=s;i<s<<r2-r2/n;i++)
					r[0][i]=r[0][i-s]+(pw[0]>>r2)&(pw[0]>>r2/n)-1;
				for(ll i=0;i<s<<r2-r2/n;i++)
					r[0][i]=r[0][i]<<r2/n;
			}
			else
			{
				ll l=1ll<<mp-(mp-1)/n-1;
				r[0].resize(l);
				for(ll i=0;i<l;i++)
					r[0][i]=i<<(mp-1)/n+1;
			}
			lp++;
		}
		else if(!(m&3))
		{
			p[0]=2,pw[0]=4,m>>=2;
			for(ll i=0;i<4;i++)
				if(Pow(i,n,4)==(k&3))
					r[0].emplace_back(i);
			if(r[0].empty())
			{
				puts("0");
				continue;
			}
			lp++;
		}
		else if(!(m&1))
			p[0]=2,pw[0]=2,m>>=1,r[0].emplace_back(k&1),lp++;
		for(ll i=3;i*i<=m;i+=2)
			if(m%i==0)
			{
				p[lp]=i,pw[lp]=1;
				while(m%i==0)
					m/=i,pw[lp]*=i;
				if(DiscreteRoots(lp))
				{
					f=0;
					break;
				}
				lp++;
			}
		if(!f)
		{
			puts("0");
			while(lp--)
				r[lp].clear();
			continue;
		}
		if(m>1)
		{
			p[lp]=pw[lp]=m,m=1;
			if(DiscreteRoots(lp))
			{
				puts("0");
				while(lp--)
					r[lp].clear();
				continue;
			}
			lp++;
		}
		for(ll i=0;i<lp;i++)
			m*=pw[i];
		for(ll i=0;i<lp;i++)
			c[i]=m/pw[i]*Pow(m/pw[i],pw[i]/p[i]*(p[i]-1)-1,pw[i])%m;
		dfs(0,0),std::sort(e,e+le),printf("%lld\n",le);
		for(ll i=0;i<le;++i,i<le?putchar(' '):putchar('\n'))
			printf("%lld",e[i]);
		while(lp--)
			r[lp].clear();
	}
	return 0;
}

关注一下下吧!!!!!求求了!!!我会回关的!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值