一.题目链接:
UVA-11916
二.题目大意:
有一个问题,有 m * n 大小的长方形区域,其中有 b 个点被阻塞,现在有 k 中颜色.
要求对未阻塞的点进行填色,每个格子只能填一种颜色,不允许出现同一列上下相邻的两个格子颜色相同.
记染色方案数为 r (mod p),输出 r.
现在问题倒过来,给出 n、b、k、r 以及阻塞点的坐标,求最小的 m.
三.分析:
很明显 m >= max(x[i]).
因此先求 1 ~ max(x[i]) 行的染色方案数.
对于第一行的非阻塞格来说,它的染色方案数为 k.
对于第 2 ~ m 行的非阻塞格来说,如果他上面是阻塞格,则染色方案数为 k,否则为 k - 1.
这样便可求出 1 ~ max(x[i]) 行的染色方案数,如果等于 r,则答案为 max(x[i]).
否则,同理计算出 1 ~ max(x[i]) + 1 行(因为第 max(x[i]) 的阻塞格会影响第 max(x[i]) + 1 行的染色数)的染色方案数
如果等于 r,则答案为 max(x[i]) + 1.
否则,设 1 ~ max(x[i]) + 1 行的染色方案数为 cnt,在 max(x[i]) + 1 行的基础上,再增加 x 行
可得:
整理可得:
到这里就可以快乐地套上模板啦!
PS:n,m ≤ 1e8,做题时看成了 nm ≤ 1e8,T 了一晚上...
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = (int)5e2;
const int mod = (int)1e8 + 7;
int m, n, k, b, r;
int x[M + 5], y[M + 5];
set < pair<int, int> > block;
ll quick(ll a, ll b)
{
ll sum = 1;
while(b)
{
if(b & 1) sum = sum * a % mod;
a = a * a % mod;
b >>= 1;
}
return sum;
}
ll inv(ll n)
{
return quick(n, mod - 2);
}
int cal()
{
int c = 0;
for(int i = 1; i <= b; ++i)
{
if(x[i] < m && !block.count(make_pair(x[i] + 1, y[i])))
++c;
}
c += n;
for(int i = 1; i <= b; ++i)
{
if(x[i] == 1)
--c;
}
return quick(k, c) * quick(k - 1, 1ll * n * m - b - c) % mod;
}
int BSGS(int a, int b)
{
map <int, int> Hash;
int t = (int)sqrt(mod) + 1;
for(int j = 0; j < t; ++j)
{
int val = quick(a, j) * b % mod;
Hash[val] = j;
}
a = quick(a, t);
if(a == 0) return b == 0 ? 1 : -1;
for(int i = 0; i <= t; ++i)
{
int val = quick(a, i);
int j = (Hash.find(val) == Hash.end() ? -1 : Hash[val]);
if(j >= 0 && i * t - j >= 0) return i * t - j;
}
return -1;
}
int work()
{
int cnt = cal();
if(cnt == r)
return m;
int c = 0;
for(int i = 1; i <= b; ++i)
{
if(x[i] == m)
++c;
}
++m;
cnt = cnt * quick(k, c) % mod * quick(k - 1, n - c) % mod;
if(cnt == r)
return m;
return BSGS(quick(k - 1, n), r * inv(cnt) % mod) + m;
}
int main()
{
int T;
scanf("%d", &T);
for(int ca = 1; ca <= T; ++ca)
{
m = 1;
block.clear();
scanf("%d %d %d %d", &n, &k, &b, &r);
for(int i = 1; i <= b; ++i)
{
scanf("%d %d", &x[i], &y[i]);
m = max(m, x[i]);
block.emplace(make_pair(x[i], y[i]));
}
printf("Case %d: %d\n", ca, work());
}
return 0;
}