码迷,mamicode.com
首页 > 其他好文 > 详细

UVa11916

时间:2016-08-26 22:51:11      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:

11916 Emoogle Grid
You have to color an M  N (1  M;N  108) two dimensional grid. You will be provided K
(2  K  108) different colors to do so. You will also be provided a list of B (0  B  500) list of
blocked cells of this grid. You cannot color those blocked cells. A cell can be described as (x; y), which
points to the y-th cell from the left of the x-th row from the top.
While coloring the grid, you have to follow these rules –
1. You have to color each cell which is not blocked.
2. You cannot color a blocked cell.
3. You can choose exactly one color from K given colors to color a
cell.
4. No two vertically adjacent cells can have the same color, i.e. cell
(x; y) and cell (x + 1; y) cannot contain the same color.
Now the great problem setter smiled with emotion and thought that he would ask the contestants
to find how many ways the board can be colored. Since the number can be very large and he doesn’t
want the contestants to be in trouble dealing with big integers; he decided to ask them to find the
result modulo 100,000,007. So he prepared the judge data for the problem using a random generator
and saved this problem for a future contest as a giveaway (easiest) problem.
But unfortunately he got married and forgot the problem completely. After some days he rediscovered
his problem and became very excited. But after a while, he saw that, in the judge data, he
forgot to add the integer which supposed to be the ‘number of rows’. He didn’t find the input generator
and his codes, but luckily he has the input file and the correct answer file. So, he asks your help to
regenerate the data. Yes, you are given the input file which contains all the information except the
‘number of rows’ and the answer file; you have to find the number of rows he might have used for this
problem.
Input
Input starts with an integer T (T  150), denoting the number of test cases.
Each test case starts with a line containing four integers N, K, B and R (0  R < 100000007)
which denotes the result for this case. Each of the next B lines will contains two integers x and y
(1  x  M, 1  y  N), denoting the row and column number of a blocked cell. All the cells will be
distinct.
Output
For each case, print the case number and the minimum possible value of M. You can assume that
solution exists for each case.
Sample Input
43
3 0 1728
4 4 2 186624
3 1
Universidad de Valladolid OJ: 11916 – Emoogle Grid 2/2
3 3
2 5 2 20
1 2
2 2
2 3 0 989323
Sample Output
Case 1: 3
Case 2: 3
Case 3: 2
Case 4: 20

技术分享

题意:

       有这样一道题目,给一个M行N列的网格涂上K种颜色,其中有B格不能涂颜色。其它每个格子都要涂一种颜色,同一列的上下两相邻格子不能涂相同颜色,给出N、M、K和B个格子的位置,求出涂色方案总数除以100000007的结果R。

       然而本题的任务和上述题目相反:已知N、K、R和B个格子的位置,求最小可能的M。

 

分析:

       一列一列地涂色,每列从上往下涂。一个格子位于第一行或者它上面的相邻格子不能涂色,则它有K种涂色方式;其它格子有K-1种涂色方式。虽然M是未知的,但M应当大于等于不能涂色的格子的行编号的最大值min_m。于是我们将整个网格分成前min_m行的不变部分和之后的若干行的可变部分(待定部分)。

       首先计算出不变部分的涂色方式数cnt1。如果cnt1<R,则说明可变部分是非空的。然后计算可变部分的第一行加上不变部分一共有cnt种涂色方法。如果cnt<R,则说明可变部分不止一行,我们需要继续添加并计算。每添加一行之后,涂色方案数都会乘以P=(K-1)^N。

假设除了不变部分以及可变部分的首行外,我们还需要添加x行,那么我们就可以得到一个模方程cnt * P^x = R,移项得P^x=R*cnt^(-1)。用大步小步算法求解即可。

技术分享
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cmath>
  4 #include <set>
  5 #include <map>
  6 typedef long long LL;
  7 using namespace std;
  8 LL mul_mod(LL A,LL B,LL MD){return A * B % MD;}
  9 LL pow_mod(LL a,LL p,LL n){
 10     if(p == 0) return 1;
 11     LL ans = pow_mod(a,p / 2,n);
 12     ans = ans * ans % n;
 13     if(p % 2 == 1) ans = ans * a % n;
 14     return ans;
 15 }
 16 // 求整数x和y,使得ax+by=d,且|x|+|y|最小。
 17 // 即使a,b在int范围内,x,y有可能会超出int
 18 void exgcd(LL a,LL b,LL& d,LL& x,LL& y){
 19     if(!b)d = a,x = 1,y = 0;
 20     else{
 21         exgcd(b,a % b,d,y,x);
 22         y -= x * (a / b);
 23     }
 24 }
 25 // 计算模n下a的逆,如果不存在逆,返回-1。a*x=1 (mod n)
 26 LL inv1(LL a,LL n){
 27     LL d,x,y;
 28     exgcd(a,n,d,x,y);
 29     return d == 1?(x+n)%n:-1;
 30 }// ax+ny=1 a,n互素则d == 1则有解
 31 LL inv(LL a,LL n){//如果n是素数
 32   return pow_mod(a,n - 2,n);
 33 }
 34 // 求解模方程a^x=b(mod n)。n为素数,无解返回-1
 35 LL log_mod(LL a,LL b,LL n){
 36     LL m,v,e = 1,i;
 37     m = (int)sqrt(n + 0.5);
 38     v = inv(pow_mod(a,m,n),n);// v=(a^-m)
 39     map<int,int> x;
 40     x[1] = 0;
 41     for(i = 1 ; i < m ; i++){
 42         e = mul_mod(e,a,n); // e = a^i % n;
 43         if(!x.count(e)) x[e] = i; // x[e]保存满足最小的i
 44     }
 45     for(i = 0 ; i < m ; i++){// 考虑a^(im),a^(im+1),,,a^(im+m-1)
 46         if(x.count(b)) return i * m + x[b];
 47         b = mul_mod(b,v,n);// b=v*b
 48     }
 49     return -1;
 50 }
 51 
 52 //带有"不能涂色格子"的网格为不变部分
 53 //全都是"可涂色格子"的网格为可变部分
 54 const int MOD = 100000007;
 55 const int maxb = 500 + 10;//b为不能涂色的格子数量
 56 int n,m,k,b,r,x[maxb],y[maxb];//m行n列的网格
 57 set<pair<int,int> >bset;  //存储不能涂色格子的坐标
 58 //计算可变部分的方案数
 59 int Count()
 60 {
 61     int c = 0;//有k种涂法的格子数,(2-m行)
 62     for(int i = 0 ; i < b ; i++)
 63         if(x[i] != m && !bset.count(make_pair(x[i] + 1,y[i])))
 64             c++;
 65     //"不能涂色格子"下面的"可涂色格子"
 66     c += n;//  c第一行有k种涂法的格子数
 67     for(int i = 0 ; i < b ; i++) if(x[i] == 1) c--;
 68     //至此完成不变部分的所有“k种涂法的格子”的计数
 69     //ans = k^c*(k-1)^(mn-b-c)
 70     return mul_mod(pow_mod(k,c,MOD),pow_mod(k - 1,(LL)n * m - b - c,MOD),MOD);
 71 }
 72 
 73 int doit()
 74 {
 75     int cnt = Count();
 76     if(cnt == r) return m; //可变部分为空
 77 
 78     int c = 0;
 79     for(int i = 0 ; i < b ; i++)
 80         if(x[i] == m)c++;//可变部分第一行中“k种涂法的格子”数
 81     m++;//m:可变部分第一行
 82     cnt = mul_mod(cnt,pow_mod(k,c,MOD),MOD);
 83     cnt = mul_mod(cnt,pow_mod(k-1,n-c,MOD),MOD);
 84     if(cnt == r) return m;//不变部分+可变部分第一行 的总方案数量
 85 
 86     return log_mod(pow_mod(k - 1,n,MOD),mul_mod(r,inv(cnt,MOD),MOD),MOD) + m;
 87     //大步小步求对数,求P^x=r*(cnt逆)。返回x+m
 88 }
 89 int main()
 90 {
 91     //freopen("f:\\1.txt","r",stdin);
 92     int T;scanf("%d",&T);
 93     for(int cas=1;cas<=T;cas++){
 94         scanf("%d%d%d%d",&n,&k,&b,&r);
 95         bset.clear();
 96         m = 1; //不变部分的最后一行
 97         for(int i = 0 ; i < b ; i++){
 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",cas,(int)doit());
103     }
104     return 0;
105 }
View Code

 

UVa11916

标签:

原文地址:http://www.cnblogs.com/cyb123456/p/5811905.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!