题意:用k种不同颜色给m*n方格涂色。其中有b个点不用涂色,给出这b个点的位置。满足上下相邻的两个位置不能涂相同颜色。
已知列数n和涂色总方案r(已经对mod取模)。求最小的行数m
解法:
1.对于m*n列方格,k中不同颜色涂色,且上下不能涂相同颜色,共:
(k*(k-1)^(m-1))^n中染色方案数
2.有若干格子不能染色,则可以跳过格子进行类似统计。得到前m1行的染色数目和第m+1行的染色数目之和cnt(m1是不用涂色的格子中最大的行数),以后每增加一行cnt*=(k-1)^n,令(k-1)^n为p,则cnt*p^(ans-m-1)=r (mod),p^(ans-m-1)=r *inv(cnt)(mod),即解一个模指数方程,使用Baby-Step算法。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<math.h>
#include<set>
#define MP make_pair
#define ll long long
using namespace std;
const ll mod = 100000007 ;
const ll maxn = 500+10 ;
ll t,n,k,b,r,m,x[maxn],y[maxn];
set<pair<ll,ll> > best;
void gcd(ll a,ll b,ll &d,ll &x,ll&y){
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 d,x,y;
gcd(a,mod,d,x,y);
return d==1?(x+mod)%mod:-1;
}
ll mul_mod(ll a,ll b){
return ((a%mod)*(b%mod))%mod;
}
ll pow_mod(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=mul_mod(ans,a),b--;
a=mul_mod(a,a),b>>=1;
}
return ans;
}
//统计不变部分的涂色种类数
ll Count(){
ll c=0;
//统计不能涂色格子下的可涂k种颜色的格子数
for(ll i=0;i<b;i++){
if(x[i]!=m&&!best.count(MP(x[i]+1,y[i]))) c++;
}
//统计第一行的可涂k种颜色的格子数
c+=n;
for(ll i=0;i<b;i++) if(x[i]==1) c--;
return mul_mod(pow_mod(k,c),pow_mod(k-1,m*n-b-c));
}
ll log_mod(ll a,ll b){
ll m,v,e=1,i;
m=(ll)sqrt(mod+0.5);
v=inv(pow_mod(a,m));
map<ll,ll> x;
x[1]=0;
for(i=1;i<m;i++){
e=mul_mod(e,a);
if(!x.count(e)) x[e]=i;
}
for(i=0;i<m;i++){
if(x.count(b)) return i*m+x[b];
b=mul_mod(b,v);
}
return -1;
}
ll doit(){
ll cnt=Count();
if(cnt==r) return m;
ll c=0;
for(ll i=0;i<b;i++)
if(x[i]==m) c++;
m++;
cnt=mul_mod(cnt,pow_mod(k,c));
cnt=mul_mod(cnt,pow_mod(k-1,n-c));
if(cnt==r) return m;
return log_mod(pow_mod(k-1,n),mul_mod(r,inv(cnt)))+m;
}
int main(){
//freopen("a.txt","r",stdin);
scanf("%lld",&t);
for(ll cas=1;cas<=t;cas++){
scanf("%lld%lld%lld%lld",&n,&k,&b,&r);
best.clear();
m=1;
for(ll i=0;i<b;i++){
scanf("%lld%lld",&x[i],&y[i]);
if(x[i]>m) m=x[i];
best.insert(MP(x[i],y[i]));
}
printf("Case %lld: %lld\n",cas,doit());
}
return 0;
}