您的位置:首页 > 其它

UVa 11916 (离散对数) Emoogle Grid

2015-03-09 06:46 295 查看
因为题目要求同列相邻两格不同色,所以列与列之间不影响,可以逐列染色。

如果一个格子的上面相邻的格子,已经被染色则染这个格子的时候,共有k-1中选择。

反过来,如果一个格子位于第一列,或者上面相邻的格子是不能被染色的格子,则共有k中选择。

虽然,矩阵的行数不定,但至少为所有不能被染色格子行标的最大值m。

分别检验一下染m行和m+1行的方案数(mod 100000007)是否为r

否则的话,后面每染一行方案数都会乘p = (k-1)n,假设前面计算出来的m+1行方案数为cnt

下面的任务就是求解 px * cnt = r (mod MOD),两边乘cnt的逆,得 px = r * cnt-1 (mod MOD)

最后加上前面的m+1行,答案为x + m + 1

最后吐槽一下我认为的坑点=_=,看到那个模想当然地以为是1e9+7,但是最后一个样例调了好久没过,后来才发现题中给的模是1e8+7

#include <cstdio>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
using namespace std;
#define MP make_pair
#define INS insert
typedef long long LL;

const int MOD = 100000007;
const int maxb = 500 + 10;
int n, m, k, b, r, x[maxb], y[maxb], fir_row;
set<pair<int, int> > Set;

int mul_mod(int a, int b)
{ return (LL) a * b % MOD; }

int pow_mod(int a, LL n)
{
int ans = 1, base = a;
while(n)
{
if(n & 1) ans = mul_mod(ans, base);
base = mul_mod(base, base);
n >>= 1;
}
return ans;
}

int inv(int a)
{ return pow_mod(a, MOD - 2); }

int log_mod(int a, int b)
{//a^x=b (mod MOD)
int m, v, e = 1, i;
m = (int)sqrt(MOD + 0.5);
v = inv(pow_mod(a, m));
map<int, int> x;
x[1] = 0;
for(i = 1; i < m; i++)
{
e = mul_mod(e, a);
if(e == b) return i;
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;
}

int solve()
{
int c = 0;//前m行涂k种颜色的格子个数
for(int i = 0; i < b; i++)
if(x[i] != m && !Set.count(MP(x[i] + 1, y[i]))) c++;
c += n - fir_row;
int cnt = mul_mod(pow_mod(k, c), pow_mod(k-1, (LL)m*n - b - c));
if(cnt == r) return m;

c = 0;//第m+1行涂k种颜色的格子个数
for(int i = 0; i < b; i++) if(x[i] == m) c++;
cnt = mul_mod(mul_mod(cnt, pow_mod(k, c)), pow_mod(k-1, n-c));
if(cnt == r) return m + 1;

int p = pow_mod(k-1, n);
int v = inv(cnt);
return log_mod(p, mul_mod(r, v)) + m + 1;
}

int main()
{
//freopen("in.txt", "r", stdin);

int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++)
{
scanf("%d%d%d%d", &n, &k, &b, &r);
Set.clear();
m = 1; fir_row = 0;
for(int i = 0; i < b; i++)
{
scanf("%d%d", &x[i], &y[i]);
Set.INS(MP(x[i], y[i]));
if(x[i] > m) m = x[i];
if(x[i] == 1) fir_row++;//第一行不能被涂色的个数
}
printf("Case %d: %d\n", kase, solve());
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: