#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)种
*/
UVA 11916 Emoogle Grid 数论
最新推荐文章于 2020-05-05 22:34:28 发布