简介:
有这样一个题目:给定一个M*N的网格涂上K种颜色,其中B个格子不能涂色,其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色
给出M,N,B个格子的位置,求出涂色方案R%100000007
这道题是上述问题的逆问题:给出N,K,R,B个格子的位置,
求出最小的M
分析:
虽然M(行数)是未知的,但是我们可以知道ta的最小值:
M=max{不能涂色的格子的行编号}
因此可以把整个网格分成两部分:不可变部分,可变部分
我们一列一列的进行涂色
如果一个格子上一个位置不能涂色,那么ta的颜色就有K种选择
其余的格子都只有K-1种选择
假设不变部分以及可变部分的第一行可行的涂色方案有cnt种
(cnt的求解要稍微麻烦一点)
那么每增加一行,涂色方案都会乘P=(K-1)^N
这样我们就得到一个模方程:
cnt*P^M=R
稍微变形得到:
P^M=R*cnt^-1
直接上bsgs求解即可
tip
当B=0的时候需要特殊求解
时刻判断cnt是不是已经等于r了
交上去是T,拍也拍不起来(数据不好造)
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<cmath>
#define ll long long
using namespace std;
const ll mod=100000007;
map<ll,int> mp;
int n,m,k,r,b,x[1000],y[1000];
set<pair<int,int> > po; //方便判断
ll KSM(ll x,ll y)
{
ll t=1;
x%=mod;
while (y)
{
if (y&1)
t=(t%mod*x%mod)%mod;
y>>=1;
x=(x%mod*x%mod)%mod;
}
return t%mod;
}
int bsgs(ll x,ll z) //x^y=z
{
x%=mod; z%=mod;
if (x==0&&z==0) return 1;
if (x==0) return -1;
mp.clear();
ll now=1;
ll m=(ll)ceil(sqrt((double)mod));
mp[1]=m+1;
for (int i=1;i<m;i++)
{
now=(now%mod*x%mod)%mod;
if (!mp[now]) mp[now]=i; //x^i=now
}
ll inv=1,tmp=KSM(x,mod-m-1);
for (int k=0;k<m;k++)
{
int i=mp[(z*inv)%mod]; //z*x^-km
if (i)
{
if (i==m+1) i=0;
return k*m+i;
}
inv=(inv%mod*tmp%mod)%mod;
}
return -1;
}
ll count()
{
int i,j;
int c1=0;
for (int i=1;i<=b;i++)
if (x[i]!=m&&!po.count(make_pair(x[i]+1,y[i]))) //计算不可涂色的方格下面有多少不受限制的方格
c1++; //其中不包含行数大于m的不受限制方格
c1+=n; //第一行都有k种涂法
for (int i=1;i<=b;i++)
if (x[i]==1) c1--; //去除不能涂色的方块
int c2=n*m-c1-b; //有k-1种涂色方法的方格
//a=k^c1 * (k-1)^c2 方案数
ll a=(KSM((ll)k,(ll)c1) * KSM((ll)(k-1),(ll)c2))%mod;
return a;
}
int doit()
{
ll cnt=count();
if (cnt==r) return m;
int c=0;
for (int i=1;i<=b;i++)
if (x[i]==m) c++; //可变部分中不受限制的方格数
cnt=(cnt * KSM((ll)k,(ll)c))%mod;
cnt=(cnt * KSM((ll)(k-1),(ll)(n-c)))%mod;
if (cnt==r) return m+1;
m++;
ll P=KSM((ll)(k-1),(ll)n);
ll rr=(r*1LL*KSM(cnt,mod-2))%mod;
return bsgs(P,rr)+m;
}
int main()
{
int T;
scanf("%d",&T);
for (int cas=1;cas<=T;cas++)
{
m=0;
scanf("%d%d%d%d",&n,&k,&b,&r);
for (int i=1;i<=b;i++)
{
scanf("%d%d",&x[i],&y[i]);
po.insert(make_pair(x[i],y[i]));
if (x[i]>m) m=x[i];
}
if (b==0)
{
ll cnt=KSM((ll)k,(ll)n);
if (cnt==r) m=1;
else
{
ll P=KSM((ll)(k-1),(ll)n);
ll rr=(r*1LL*KSM(cnt,mod-2))%mod;
m=bsgs(P,rr)+1;
}
printf("Case %d: %d\n",cas,m);
}
else printf("Case %d: %d\n",cas,doit());
}
return 0;
}