这题主要问题在于我们要求一个大数对大数的逆元。
我们考虑把大模数分解质因数之后就可以O(mlogV)的上下约分,然后看分母是否和大模数互质,以判断是否存在逆元。
然后这个大数如何质因数分解呢?我们可以用pollard-rho+miller-rabin来做。复杂度O(n1/4)
pollard-rho怎么做呢?大概就是你每次随机若干个数去试,看他们是不是n的因子,这样成功概率较低,怎么办呢?你看gcd(x,n)是否不为1,如果不为1,则找到了一个因数,这样成功率就大了一些了。我们再试图提高成功率,每次随机俩数,看他们的差是否可以。然后我们怎么随机这些数呢?我们可以利用这样一个伪随机数生成函数:xi+1=xi∗xi+a来生成。只给他随机一个x0和a即可。
然后伪随机数可能会产生循环,这时我们要退出,重新随机。怎么判断是否出了循环呢?
floyd判圈!想象一下,假设有两个小孩子在一个“可以无限向前跑”的跑道上赛跑,同时出发。但其中一个小孩的速度是另一个的两倍。如果跑道是直的,跑得快的小孩永远在前面;但如果跑道有环,则跑得快的小孩将“追上”跑得慢的小孩。
好的,我们得到了n的一个因数t,然后递归去分解t和n/t。直到n为质数或1返回。
那么我们还需要判断质数!怎么办呢!miller-rabin素数检测法!
根据费马小定理和二次探测来检测素数,随机S个,成功率高达99.999%,且复杂度只有O(Slog2n)
当然你需要O(1)快速乘!
改了一天qaq,原因竟是快速乘需要取模!怎么以前都没发现呢!
至此,tjoi2017完结~~~
回忆起去年省选赛场上的自己,真的是啥也不会qaq(好像现在也还是啥也不会【逃】)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 10010
#define ld long double
#define eps 1e-8
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline ll read(){
ll x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,K,tot;
ll b[N],a[22][N],fac[N],prime[N],num0[N],num[N];
inline ll mul(ll x,ll y,ll mod){
ll res=x*y-(ll)((ld)x/mod*y+eps)*mod;res%=mod;return res<0?res+mod:res;
}
inline ll ksm(ll x,ll k,ll mod){
ll res=1;for(;k;k>>=1,x=mul(x,x,mod)) if(k&1) res=mul(res,x,mod);return res;
}
inline ll fabs(ll x){return x<0?-x:x;}
inline bool check_p(ll a,ll y,int cnt,ll mod){
ll x=ksm(a,y,mod);if(x==1||x==mod-1) return 1;
for(int i=1;i<=cnt;++i){
x=mul(x,x,mod);
if(x==1) return 0;
if(x==mod-1) return 1;
}return 0;
}
inline bool miller_rabin(ll x){
if(x==2) return 1;
if(x%2==0) return 0;
ll y=x-1;int cnt=0;
while(y%2==0) y>>=1,++cnt;
for(int i=1;i<=5;++i) if(!check_p(rand()%(x-2)+1,y,cnt,x)) return 0;
return 1;
}
inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
inline ll pollard_rho(ll a,ll mod){
ll x=rand()%mod,y=x,k=2,g=1;
for(ll i=1;g==1;++i){
x=mul(x,x,mod)+a;x%=mod;
g=gcd(fabs(x-y),mod);if(i==k){k<<=1;y=x;}
}return g;
}
void findfac(ll x){
if(x==1) return;
if(miller_rabin(x)){fac[++tot]=x;return;}
ll t=x;while(t==x) t=pollard_rho(rand()%(x-1)+1,x);
findfac(t);findfac(x/t);
}
int main(){
// freopen("boat14.in","r",stdin);
n=read();m=read();K=read();srand(20000712);
for(int i=1;i<=m;++i) b[i]=read();
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) a[i][j]=read();
while(K--){
int id=read();ll mod=read();tot=0;findfac(mod);
sort(fac+1,fac+tot+1);int cnt=0;ll phi=mod;
for(int i=1;i<=tot;++i){
if(fac[i]!=fac[i-1]) prime[++cnt]=fac[i],num0[cnt]=0,num[cnt]=0,phi-=phi/fac[i];num0[cnt]++;
}ll ans=1,inv=1;
for(int i=1;i<=m;++i){
ll x=b[i];
for(int j=1;j<=cnt;++j)
while(x%prime[j]==0) x/=prime[j],++num[j];
ans=mul(ans,x,mod);
}for(int i=1;i<=m;++i){
ll x=a[id][i];
for(int j=1;j<=cnt;++j)
while(x%prime[j]==0) x/=prime[j],--num[j];
inv=mul(inv,x,mod);
}bool flag=0;
for(int i=1;i<=cnt;++i) if(num[i]<0){puts("-1");flag=1;break;}if(flag) continue;
for(int i=1;i<=cnt;++i) if(num[i]) ans=mul(ans,ksm(prime[i],num[i],mod),mod);
ans=mul(ans,ksm(inv,phi-1,mod),mod);
printf("%lld\n",ans);
}return 0;
}