UVA 11916 Emoogle Grid 数论

#include <iostream>
#include <algorithm>
#include <math.h>
#include <set>
#include <map>
using namespace std;
#define LL long long
#define maxn 505
const LL mod=100000007;
LL n,m,k,b,r,x[505],y[505];
set<pair<LL,LL> >mm;
void gcd(LL a,LL b,LL &d,LL &x,LL &y)//拓展欧几里得定理,求ax+by=gcd(a,b)的一组解
{
    if(!b){d=a;x=1;y=0;}
    else{gcd(b,a%b,d,y,x);y-=x*(a/b);}
}
LL inv(LL a,LL n)//求得a在模n条件下的逆
{
   LL d,x,y;
   gcd(a,n,d,x,y);
   return d==1?(x+n)%n:-1;
}
LL pows(LL a,LL b)//快速幂求a^b
{
    LL s=1;
    while(b)
    {
        if(b&1)
            s=(s*a)%mod;
        a=(a*a)%mod;
        b=b>>1;
    }
    return s;
}
//求解模方程a^x=b(mod n)。n为素数,无解返回-1
LL log_mod (LL a,LL b,LL n)
{
    LL m,v,e=1,i;
    m=(LL)sqrt(n+0.5);
    v=inv(pows(a,m),n);
    map<int,int>x;
    x[1]=0;
    for(i=1;i<m;i++)
    {
        e=(e*a)%n;
        if(!x.count(e))x[e]=i;
    }
    for(i=0;i<m;i++)
    {
        if(x.count(b))return i*m+x[b];
        b=(b*v)%n;
    }
    return -1;
}
LL fun()
{
    LL i,j,cnt,num=0;
    for(i=0;i<b;i++)
        if(x[i]!=m&&!mm.count(make_pair(x[i]+1,y[i])))num++;
    num+=n;
    for(i=0;i<b;i++)
        if(x[i]==1)num--;
    cnt=(pows(k,num)*pows(k-1,n*m-b-num))%mod;
    if(cnt==r)return m;
    num=0;
    for(i=0;i<b;i++)
        if(x[i]==m)num++;
    cnt=(cnt*pows(k,num))%mod;
    cnt=(cnt*pows(k-1,n-num))%mod;
    m++;
    return log_mod(pows(k-1,n),(r*inv(cnt,mod))%mod,mod)+m;
}
int main()
{
    LL T,tt=0;
    cin>>T;
    while(T--)
    {
        LL i,j;
        cin>>n>>k>>b>>r;
        mm.clear();
        m=1;
        for(i=0;i<b;i++)
        {
            cin>>x[i]>>y[i];
            if(x[i]>m)m=x[i];
            mm.insert(make_pair(x[i],y[i]));
        }
        cout<<"Case "<<++tt<<": "<<fun()<<endl;
    }
    return 0;
}
/*
    求一个数的逆的意义:假定有两个整数a和b,其中a/b使整数,且a和b除以mod的余数是aa,bb,
则a/b除以mod的余数等于(aa*bb^(-1))%mod。
    本题中,cnt表示含有不能涂色格子的部分加上新增的一行的可涂方案,之后每加一行,那方案数就要乘以pow(k-1,n),
从而可知最终方案数M=cnt*(k-1)^(n*t),M%mod=r.inv()为求逆函数。则(k-1)^(n*t)%mod=M/cnt=(r*inv(cnt))%mod
    在解模方程a^x=b(mod)就可以求得t,其中(a=(k-1)^n,b=(r*inv(cnt)%mod))

    对于含有不能涂色格子的部分,第一行和在它之上是不能涂色格子的格子有k种涂法,其余(k-1)种
*/

你可能感兴趣的:(数论,乘法的逆,模方程)