【离散对数 && 逆元 && 概率论】UVA - 11916 Emoogle Grid
2017-10-21 10:27
274 查看
Problem Description
有这样一道题,要给一个M行N列的网格涂上K种颜色,其中有B个格子不能涂色。其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色。给出M, N, K 和 B个格子的位置,求出涂色方案总数除以100000007的结果R。
本题的任务和这个相反:已知N, K, R 和 B个格子的位置,求最小的可能的M。
思路:
一列一列地涂色,每列从上往下涂。如果一个格子位于第一行,或者它上面相邻格子不能涂色,则它有K种涂色方法;其他可涂色格有K-1种方法。虽然M是未知的。但由于M至少应当等于不能涂色的格子的行编号的最大值,因此可以把整个网络分成不变部分和可变部分
假定不变部分和可变部分的第一行一共有cnt种涂色法,则每加一行之后,涂色方案数都会乘以P = (K - 1)^N。这样,我们得到了一种模方程cnt*P^M = R, 移项得P^M = R * cnt^-1。用大步小步算法求解即可。注意要事先判断 M = L是否满足条件,否则不仅“可变部分”为空,“不变部分”也是不完整的。
求离散对数 大步小步算法:
解模方程a^x ≡ b(mod n) 求解 x。我们只讨论n为素数的情况
因为n是素数,只要a不为0, 一定存在逆a^-1。
根据欧拉定理,只需检查x = 0, 1, 2, …, n-1是不是解即可。因为a^(n-1) ≡ 1(mod n), 当x超过n-1时a^x就开始循环了,我们先检查前m项(m = sqrt(n+0.5)),即a^0, a^1, …, a^(m-1)模n的值是否为b,并把a^i mod n保存在ei里,求出a^m的逆a^(-m)。
下面考虑a^m, a^(m+1), …, a^(2*m - 1)。这次不用一一检查,因为如果它们中有解,则相当于存在i使得e^i * a^m ≡ b(mod n)。两边同乘a^(-m)得ei ≡ bb(mod n), 其中bb = a^(-m)*b(mod n)。这样只需检查是否真的存在ei等于这个bb即可。
复杂度O(n) 降低到(sqrt(n)logn)。
有这样一道题,要给一个M行N列的网格涂上K种颜色,其中有B个格子不能涂色。其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色。给出M, N, K 和 B个格子的位置,求出涂色方案总数除以100000007的结果R。
本题的任务和这个相反:已知N, K, R 和 B个格子的位置,求最小的可能的M。
思路:
一列一列地涂色,每列从上往下涂。如果一个格子位于第一行,或者它上面相邻格子不能涂色,则它有K种涂色方法;其他可涂色格有K-1种方法。虽然M是未知的。但由于M至少应当等于不能涂色的格子的行编号的最大值,因此可以把整个网络分成不变部分和可变部分
假定不变部分和可变部分的第一行一共有cnt种涂色法,则每加一行之后,涂色方案数都会乘以P = (K - 1)^N。这样,我们得到了一种模方程cnt*P^M = R, 移项得P^M = R * cnt^-1。用大步小步算法求解即可。注意要事先判断 M = L是否满足条件,否则不仅“可变部分”为空,“不变部分”也是不完整的。
求离散对数 大步小步算法:
解模方程a^x ≡ b(mod n) 求解 x。我们只讨论n为素数的情况
因为n是素数,只要a不为0, 一定存在逆a^-1。
根据欧拉定理,只需检查x = 0, 1, 2, …, n-1是不是解即可。因为a^(n-1) ≡ 1(mod n), 当x超过n-1时a^x就开始循环了,我们先检查前m项(m = sqrt(n+0.5)),即a^0, a^1, …, a^(m-1)模n的值是否为b,并把a^i mod n保存在ei里,求出a^m的逆a^(-m)。
下面考虑a^m, a^(m+1), …, a^(2*m - 1)。这次不用一一检查,因为如果它们中有解,则相当于存在i使得e^i * a^m ≡ b(mod n)。两边同乘a^(-m)得ei ≡ bb(mod n), 其中bb = a^(-m)*b(mod n)。这样只需检查是否真的存在ei等于这个bb即可。
复杂度O(n) 降低到(sqrt(n)logn)。
#include<bits/stdc++.h> using namespace std; #define LL long long const int maxn = 510; const LL mod = 100000007; int x[maxn], y[maxn], n, k, b, r, m; struct node { int xx, yy; bool operator < (const node &b) const{ if(xx == b.xx) return yy < b.yy; else return xx < b.xx; } }; set< node > q; LL mul_mod(LL a, LL b) { return (a*b)%mod; } LL Pow(LL a, LL n) { LL sum = 1; while(n) { if(n&1) sum = mul_mod(sum, a); a = mul_mod(a, a); n >>= 1; } return sum; } void extend_gcd(LL a, LL b, LL &d, LL &x, LL &y) { if(!b){d = 1; x = 1; y = 0;} else {extend_gcd(b, a%b, d, y, x); y -= x*(a/b);} } LL inv(LL a, LL n)//求逆元 ax≡1modn,x是a的逆元 { LL d, x, y; extend_gcd(a, n, d, x, y); return d == 1 ? (x+n)%n : -1; } int log_mod(int a, int b)//求离散对数 { int m, v, e = 1, i; m = (int)sqrt(mod+0.5);//避免浮点误差 v = inv(Pow(a, m), mod);//求a^m的对mod取模 的逆元 map<int, int> x; x[1] = 0;//e0=a^0%mod, 所以x[a^0] = 0 for(i = 1; i < m; i++) { e = mul_mod(e, a);//a^i%mod if(!x.count(e)) x[e] = i;//i对应的是几次方 } for(i = 0; i < m; i++) { if(x.count(b)) return i*m + x[b];//如果存在b`== ei,有解返回x[b]次方 + 多少个m次方 b = mul_mod(b, v); } return -1; } int Count()//求m行的时候有多少种方案 { int num = 0, i;//num 用来记录涂k种方法的格子有多少个 for(i = 0; i < b; i++) { if(x[i] != m && !q.count((node){x[i]+1, y[i]}))//每个不能涂色的格子的下一行都能涂k种方法,因为只有m行,所以x[i] != m num++; } num += n;//第一行的格子能涂k种颜色 for(i = 0; i < b; i++) { if(x[i] == 1) num--;//第一行不能涂色的格子删除 } return mul_mod(Pow(k, num), Pow(k-1, (LL)n*m-num-b));//返回涂色方案数 } int doit() { int cnt = Count(), i;//求m行的时候有多少种方案 if(cnt == r) return m;//满足输出 int num = 0;//m+1行有多少个可以涂K种颜色的格子 for(i = 0; i < b; i++) { if(x[i] == m) num++; } m++; cnt = mul_mod(cnt, Pow(k, num)); cnt = mul_mod(cnt, Pow(k-1, n-num));//更新m+1行后的总方案数 if(cnt == r) return m;//满足输出 return log_mod(Pow(k-1, n), mul_mod(r, inv(cnt, mod))) + m;//可变部分 } int main() { int T, Case = 1; scanf("%d", &T); while(T--) { scanf("%d %d %d %d", &n, &k, &b, &r); m = 1; q.clear();//初始化,m至少为1 for(int i = 0; i < b; i++) { scanf("%d %d", &x[i], &y[i]); m = max(x[i], m);//找出不能涂色的点的最大的行 q.insert((node){x[i], y[i]});//将所有点存起来 } printf("Case %d: %d\n", Case++, doit()); } return 0; }
相关文章推荐
- UVA - 11916 Emoogle Grid (离散对数取模)
- UVa 11916 (离散对数) Emoogle Grid
- UVA 11916 Emoogle Grid(离散对数、BSGS算法)
- UVa 11916 - Emoogle Grid (离散对数)
- [离散对数] uva 11916 Emoogle Grid
- [离散对数] uva 11916 Emoogle Grid
- UVA 11916 Emoogle Grid 离散对数 大步小步算法
- UVA 11916 Emoogle Grid 数论
- UVA 11916 - Emoogle Grid(数论)
- (UVA)11916 Emoogle Grid
- uva 11916 Emoogle Grid (BSGS)
- uva 11916 - Emoogle Grid(大步小步算法)
- [uva 11916]Emoogle Grid 数学 BSGS
- UVA11916 Emoogle Grid
- UVA 11916 Emoogle Grid(同余模)
- uva11916 - Emoogle Grid 网格涂色
- UVA 11916 Emoogle Grid(大步小步算法(解模方程对数) 快速幂 模的逆)
- uva11916 Emoogle Grid
- [uva11916] Emoogle Grid (离散对数)
- Emoogle Grid (方案数,逆元求解,对数求解)