[TJOI2017]龙舟

题意:求(frac{a}{b})Mod(M)的值,a,b是很多个数的乘积。
首先,要对(frac{a}{b})进行约分,但是,因为a,b很大,难以求出他们的gcd。
我们发现:只要约分后的b和M互质,就能求出b的逆元,进而求出答案。
因此,我们只要考虑M的质因数即可。
先用Pollard-rho将M分解,再用M的质因数去分解a,b即可。
若分解后发现对于某一质因数,b的次数大于a的次数,则无解。
否则,同时约去即可。
代码:

#include <stdio.h>
#include <stdlib.h>
#define ll long long
ll ksc(ll a,ll b,ll c)
{
	return (a*b-(ll)((long double)a/c*b)*c+c)%c; 
}
ll ksm(ll a,ll b,ll c)
{
	ll jg=1;
	while(b>0)
	{
		if(b&1)
			jg=ksc(jg,a,c);
		a=ksc(a,a,c);
		b=(b>>1);
	}
	return jg;
}
int pri[10]={2,3,5,7,11,13,17,19,23,29};
bool miller(int a,ll x)
{
	ll t=x-1;int s=0;
	while(t%2==0)
		t/=2,s+=1;
	ll z=ksm(a,t,x);
	for(int i=0;i<s;i++)
	{
		ll t=ksc(z,z,x);
		if(t==1&&z!=1&&z!=x-1)
			return false;
		z=t;
	}
	return z==1;
}
bool isprime(ll x)
{
	for(int i=0;i<10;i++)
	{
		if(x==pri[i])
			return true;
	}
	for(int i=0;i<10;i++)
	{
		if(!miller(pri[i],x))
			return false;
	}
	return true;
}
ll gcd(ll a,ll b)
{
    while(b!=0)
    {
        ll t=a%b;
        a=b;b=t;
    }
    return a;
}
ll rho(ll p)
{
	while(1)
	{
		int y=rand()%1000000000;
		ll x1=1,x2=(y+1)%p;
		while(x1!=x2)
		{
			ll t=x1-x2;
			if(t<0)t=-t;
			ll g=gcd(t,p);
			if(g!=1&&g!=p)
				return g;
			x1=(ksc(x1,x1,p)+y)%p;
			x2=(ksc(x2,x2,p)+y)%p;
			x2=(ksc(x2,x2,p)+y)%p;
		}
	}
	return -1;
}
ll fa[70],ys[70];int sl=0;
void factor(ll p)
{
	if(isprime(p))
	{
		fa[sl++]=p;
		return;
	}
	ll g=rho(p);
	factor(g);
	factor(p/g);
}
int cmp(const void*a2,const void*b2)
{
	ll a=*(ll*)a2,b=*(ll*)b2;
	if(a>b)
		return 1;
	else if(a<b)
		return -1;
	return 0;
}
ll sa[10010],sb[10010];
ll getans(ll b[10010],ll a[10010],int m,ll M)
{
	sl=0;factor(M);
	qsort(fa,sl,sizeof(ll),cmp);
	int s=0;
	for(int i=0;i<sl;i++)
	{
		if(i==0||fa[i]!=fa[i-1])
			ys[s++]=fa[i];
	}
	ll phi=M;
	for(int i=0;i<s;i++)
		phi=phi/ys[i]*(ys[i]-1);
	int ma[70]={0},mb[70]={0};
	for(int i=1;i<=m;i++)
	{
		sa[i]=a[i];sb[i]=b[i];
		for(int j=0;j<s;j++)
		{
			while(sa[i]%ys[j]==0)
			{
				ma[j]+=1;
				sa[i]/=ys[j];
			}
			while(sb[i]%ys[j]==0)
			{
				mb[j]+=1;
				sb[i]/=ys[j];
			}
		}
	}
	for(int i=0;i<s;i++)
	{
		int t=ma[i];
		if(mb[i]<t)t=mb[i];
		ma[i]-=t;
		mb[i]-=t;
		if(ma[i]>0)
			return -1;
	}
	ll zb=1,za=1;
	for(int i=1;i<=m;i++)
	{
		za=ksc(za,sa[i],M);
		zb=ksc(zb,sb[i],M);
	}
	for(int i=0;i<s;i++)
		zb=ksc(zb,ksm(ys[i],mb[i],M),M);
	return ksc(zb,ksm(za,phi-1,M),M);
}
ll A[21][10010],B[10010];
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++)
		scanf("%lld",&B[i]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
			scanf("%lld",&A[i][j]);
	}
	for(int i=0;i<k;i++)
	{
		int x;ll M;
		scanf("%d%lld",&x,&M);
		printf("%lld
",getans(B,A[x],m,M));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lnzwz/p/12223460.html