zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    从Unity3D编译器升级聊起Mono
    RxJava系列6(从微观角度解读RxJava源码)
    RxJava系列5(组合操作符)
    RxJava系列4(过滤操作符)
    RxJava系列3(转换操作符)
    RxJava系列2(基本概念及使用介绍)
    RxJava系列1(简介)
    给 Android 开发者的 RxJava 详解
    深入浅出RxJava就这一篇就够了
    android非法字符的判定、表情符号的判定
  • 原文地址:https://www.cnblogs.com/lnzwz/p/12223460.html
Copyright © 2011-2022 走看看