#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)种 */