因为题目要求同列相邻两格不同色,所以列与列之间不影响,可以逐列染色。
如果一个格子的上面相邻的格子,已经被染色则染这个格子的时候,共有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
1 #include <cstdio> 2 #include <map> 3 #include <set> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 #define MP make_pair 8 #define INS insert 9 typedef long long LL; 10 11 const int MOD = 100000007; 12 const int maxb = 500 + 10; 13 int n, m, k, b, r, x[maxb], y[maxb], fir_row; 14 set<pair<int, int> > Set; 15 16 int mul_mod(int a, int b) 17 { return (LL) a * b % MOD; } 18 19 int pow_mod(int a, LL n) 20 { 21 int ans = 1, base = a; 22 while(n) 23 { 24 if(n & 1) ans = mul_mod(ans, base); 25 base = mul_mod(base, base); 26 n >>= 1; 27 } 28 return ans; 29 } 30 31 int inv(int a) 32 { return pow_mod(a, MOD - 2); } 33 34 int log_mod(int a, int b) 35 {//a^x=b (mod MOD) 36 int m, v, e = 1, i; 37 m = (int)sqrt(MOD + 0.5); 38 v = inv(pow_mod(a, m)); 39 map<int, int> x; 40 x[1] = 0; 41 for(i = 1; i < m; i++) 42 { 43 e = mul_mod(e, a); 44 if(e == b) return i; 45 if(!x.count(e)) x[e] = i; 46 } 47 for(i = 0; i < m; i++) 48 { 49 if(x.count(b)) return i*m + x[b]; 50 b = mul_mod(b, v); 51 } 52 return -1; 53 } 54 55 int solve() 56 { 57 int c = 0;//前m行涂k种颜色的格子个数 58 for(int i = 0; i < b; i++) 59 if(x[i] != m && !Set.count(MP(x[i] + 1, y[i]))) c++; 60 c += n - fir_row; 61 int cnt = mul_mod(pow_mod(k, c), pow_mod(k-1, (LL)m*n - b - c)); 62 if(cnt == r) return m; 63 64 c = 0;//第m+1行涂k种颜色的格子个数 65 for(int i = 0; i < b; i++) if(x[i] == m) c++; 66 cnt = mul_mod(mul_mod(cnt, pow_mod(k, c)), pow_mod(k-1, n-c)); 67 if(cnt == r) return m + 1; 68 69 int p = pow_mod(k-1, n); 70 int v = inv(cnt); 71 return log_mod(p, mul_mod(r, v)) + m + 1; 72 } 73 74 int main() 75 { 76 //freopen("in.txt", "r", stdin); 77 78 int T; 79 scanf("%d", &T); 80 for(int kase = 1; kase <= T; kase++) 81 { 82 scanf("%d%d%d%d", &n, &k, &b, &r); 83 Set.clear(); 84 m = 1; fir_row = 0; 85 for(int i = 0; i < b; i++) 86 { 87 scanf("%d%d", &x[i], &y[i]); 88 Set.INS(MP(x[i], y[i])); 89 if(x[i] > m) m = x[i]; 90 if(x[i] == 1) fir_row++;//第一行不能被涂色的个数 91 } 92 printf("Case %d: %d ", kase, solve()); 93 } 94 95 return 0; 96 }