[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\n",getans(B,A[x],m,M));
}
return 0;
}