uva 11916 Emoogle Grid

题意:用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
", t, doit());
103     }
104 }
View Code
原文地址:https://www.cnblogs.com/ITUPC/p/4942255.html