标签:
题意:用K种颜色给一个N*M的格子涂色。其中有B个格子是不能涂色的。涂色时满足同一列上下紧邻的两个格子的颜色不同。所有的涂色方案模100000007后为R。现在给出M、K、B、R,求一个最小的N,满足题意。
思路:分成两个部分。设给出的B个不能涂的格子的最大行坐标为m。 首先,我们能计算出前m行的方案数cnt,若cnt=r,则m就是答案。每增加一行,就会增加(K-1)^m种方法,接着令p=(K-1)^M,我们能计算出前m+1行的方案数cnt,若cnt=r 则答案为 m+1。否则,设下面还需要t行,那么有cnt*(p)^t%100000007=R,将cnt的逆元乘到右侧得到新的 p^t=R*reverse(cnt)。那么就成了求最小的t满足p^t%100000007=R*reverse(cnt)。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<set> 5 #include<map> 6 using namespace std; 7 8 const int MOD = 100000007; 9 const int maxb = 500 + 10; 10 int n, m, k, b, r, x[maxb], y[maxb]; 11 set<pair<int, int> > bset; 12 13 int pow_mod(int a, long long p) 14 { 15 if(p == 0) 16 return 1; 17 int ans = pow_mod(a, p/2); 18 ans = (long long)ans * ans % MOD; 19 if(p%2) 20 ans = (long long)ans * a % MOD; 21 return ans; 22 } 23 24 int mul_mod(int a, int b) 25 { 26 return (long long)a * b % MOD; 27 } 28 29 int inv(int a) 30 { 31 return pow_mod(a, MOD-2); 32 } 33 34 int log_mod(int a, int b) 35 { 36 int m, v, e = 1, i; 37 m = (int)sqrt(MOD); 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 (!x.count(e)) x[e] = i; 45 } 46 for(i = 0; i < m; i++) 47 { 48 if(x.count(b)) return i*m + x[b]; 49 b = mul_mod(b, v); 50 } 51 return -1; 52 } 53 54 // 计算可变部分的方案数 55 int count() 56 { 57 int c = 0; // 有k种涂法的格子数 58 for(int i = 0; i < b; i++) 59 { 60 if(x[i] != m && !bset.count(make_pair(x[i]+1, y[i]))) c++; // 不可涂色格下面的可涂色格 61 } 62 c += n; // 第一行所有空格都有k种涂法 63 for(int i = 0; i < b; i++) 64 if(x[i] == 1) c--; // 扣除那些不能涂色的格子 65 66 // ans = k^c * (k-1)^(mn - b - c) 67 return mul_mod(pow_mod(k, c), pow_mod(k-1, (long long)m*n - b - c)); 68 } 69 70 int doit() 71 { 72 int cnt = count(); 73 if(cnt == r) return m; // 不变部分为空 74 75 int c = 0; 76 for(int i = 0; i < b; i++) 77 if(x[i] == m) 78 c++; // 可变部分第一行中有k种涂法的格子数 79 m++; // 多了一行(可变部分的第一行) 80 cnt = mul_mod(cnt, pow_mod(k, c)); 81 cnt = mul_mod(cnt, pow_mod(k-1, n - c)); 82 if(cnt == r) return m; // 此时cnt为不变部分和可变部分第一行的方案总数 83 84 return log_mod(pow_mod(k-1,n), mul_mod(r, inv(cnt))) + m; 85 } 86 87 int main() 88 { 89 int T; 90 scanf("%d", &T); 91 for(int t = 1; t <= T; t++) 92 { 93 scanf("%d%d%d%d", &n, &k, &b, &r); 94 bset.clear(); 95 m = 1; 96 for(int i = 0; i < b; i++) 97 { 98 scanf("%d%d", &x[i], &y[i]); 99 if(x[i] > m) m = x[i]; // 更新不变部分的行数 100 bset.insert(make_pair(x[i], y[i])); 101 } 102 printf("Case %d: %d\n", t, doit()); 103 } 104 }
标签:
原文地址:http://www.cnblogs.com/ITUPC/p/4942255.html