Petrozavodsk Summer-2015. Ivan Smirnov Contest 1 B Bloom
http://opentrains.snarknews.info/~ejudge/team.cgi?contest_id=001463
题目大意:
给出$n$个$x$,$m$个$y$,问有多少个hash函数 $y \equiv Ax + B (mod \ p)$, $p$是质数使得对$x$的集合加密后得到$y$的集合。
题解:
首先将所有$x$ mod $p$后去重。 剩下$n$个不同的$x$,$m$个不同的$y$。
ps: 以下公式均在mod p域下,因此省略mod p。
如果$A = 0$,那么只可能$m = 1$, $B = y_0$
如果$A \neq 0$,因为p是质数,所以$A * x_i \neq A * x_j$. 那么必须$ n = m $
如果hash函数没有那个$B$,只有$y = Ax$怎么做呢?
考虑将每个数写成原根$g^i$的形式。
定义数组s, s[i] = 1 当且仅当 存在某个$x$,$x = g^i$.
定义数组t, t[i] = 1 当且仅当 存在某个$y$,$y = g^i$.
一个$A = g^k$合法当且仅当将s数组循环右移$k$位和t数组重合。
只要将t数组复制一遍做一次kmp就可以求出所有的$k$了。
再考虑如何把B给算进去.
假设$ y_i = A * x_i + B $. 两边对$i$求和。
记$sx = \sum\limits_{i=0}^{n - 1}x_i$, $sy = \sum\limits_{i=0}^{n - 1}y_i$
那么有$sy = A * sx + n * B$, $ B = \frac{sy - A * sx}{n}$ 是唯一的!
令$x_{i}^{'} = x_{i} - \frac{sx}{n}$ $y_{i}^{'} = y_{i} - \frac{sy}{n}$
问题就转化为$y_{i}^{'} = A * x_{i}^{'}$ 这两个问题是完全等价的.
另外还有一些小细节:比如n = p的时候,分母n是没有逆元的,所以要特判断。
还有如果存在某个$x_{i}^{'} = 0$, 不存在某个$y_{i}^{'} = 0$ 或者反过来,都是无解的。(0不能表示为$g^i$, 所以也要特判)。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define MP make_pair 5 #define MAXN 1000010 6 int mod; 7 vector<int> xi, yi; 8 vector<pair<int, int> > ans; 9 10 inline int add(int x, int y){return (x + y) % mod;} 11 inline int sub(int x, int y){return (x - y + mod) % mod;} 12 inline int mul(int x, int y){return 1ll * x * y % mod;} 13 14 int power(int x, int p) 15 { 16 int res = 1; 17 for (; p; p >>= 1) 18 { 19 if (p & 1) res = mul(res, x); 20 x = mul(x, x); 21 } 22 return res; 23 } 24 25 int inv(int x) 26 { 27 return power(x, mod - 2); 28 } 29 30 int find_proot(int p) 31 { 32 static int pr[MAXN]; 33 static int flag[MAXN]; 34 for (int i = 2; i < MAXN; ++i) 35 { 36 if (!flag[i]) pr[++pr[0]] = i; 37 for (int j = 1; j <= pr[0] && i * pr[j] < MAXN; ++j) 38 { 39 flag[i * pr[j]] = 1; 40 if (i % pr[j] == 0) break; 41 } 42 } 43 44 int g = 2; 45 while (true) 46 { 47 int fl = 1, pp = p - 1; 48 for (int i = 1; i <= pr[0] && pr[i] <= p; ++i) 49 { 50 if (pp % pr[i] == 0 && power(g, pp / pr[i]) == 1) 51 { 52 fl = 0; 53 break; 54 } 55 } 56 if (fl) return g; 57 58 ++g; 59 } 60 return -1; 61 } 62 63 vector<int> calc_shift(int *s, int *t, int len) 64 { 65 static int nxt[MAXN]; 66 nxt[0] = nxt[1] = 0; 67 int j; 68 for (int i = 2; i <= len; ++i) 69 { 70 j = nxt[i - 1]; 71 while (j && s[j] != s[i - 1]) 72 j = nxt[j]; 73 nxt[i] = s[i - 1] == s[j]? j + 1: 0; 74 } 75 76 for (int i = 0; i < len; ++i) 77 t[len + i] = t[i]; 78 79 j = 0; 80 vector<int> res; 81 for (int i = 0; i < 2 * len - 1; ++i) 82 { 83 while (j && t[i] != s[j]) 84 j = nxt[j]; 85 if (t[i] == s[j]) ++j; 86 if (j == len) 87 { 88 j = nxt[j]; 89 res.push_back(i - len + 1); 90 } 91 } 92 return res; 93 } 94 95 void solve(int n, int m, int p) 96 { 97 if (n < m) return; 98 if (m == 1) ans.push_back(MP(0, yi[0])); 99 if (n != m) return; 100 if (n == p) 101 { 102 for (int a = 1; a < p; ++a) 103 { 104 for (int b = 0; b < p; ++b) 105 ans.push_back(MP(a, b)); 106 } 107 return; 108 } 109 110 int _n = inv(n); 111 int sx = 0, dx; 112 int sy = 0, dy; 113 114 for (auto x: xi) sx = add(sx, x); 115 for (auto y: yi) sy = add(sy, y); 116 dx = mul(sx, _n); 117 dy = mul(sy, _n); 118 119 int g = find_proot(p); 120 static int lg[MAXN]; 121 memset(lg, -1, sizeof(lg)); 122 for (int i = 0; i < p - 1; ++i) 123 lg[power(g, i)] = i; 124 for (int i = 1; i <= p - 1; ++i) 125 assert(lg[i] != -1); 126 127 static int s[MAXN]; 128 static int t[MAXN * 2]; 129 130 int x_zero = 0, y_zero = 0; 131 for (auto x: xi) 132 { 133 if (x == dx) ++x_zero; 134 else s[lg[sub(x, dx)]] = 1; 135 } 136 for (auto y: yi) 137 { 138 if (y == dy) ++y_zero; 139 else t[lg[sub(y, dy)]] = 1; 140 } 141 if (x_zero != y_zero) return; 142 143 vector<int> a_list = calc_shift(s, t, p - 1); 144 for (auto a: a_list) 145 { 146 a = power(g, a); 147 int b = mul(sub(sy, mul(a, sx)), _n); 148 ans.push_back(MP(a, b)); 149 } 150 } 151 152 int main() 153 { 154 //freopen("in.txt", "r", stdin); 155 int n, m, p, x, y; 156 scanf("%d %d %d", &n, &m, &p), mod = p; 157 for (int i = 0; i < n; ++i) 158 { 159 scanf("%d", &x); 160 xi.push_back(x % p); 161 } 162 for (int i = 0; i < m; ++i) 163 { 164 scanf("%d", &y); 165 yi.push_back(y); 166 } 167 sort(xi.begin(), xi.end()); 168 xi.erase(unique(xi.begin(), xi.end()), xi.end()); 169 170 sort(yi.begin(), yi.end()); 171 yi.erase(unique(yi.begin(), yi.end()), yi.end()); 172 173 n = xi.size(); 174 m = yi.size(); 175 176 solve(n, m, p); 177 178 printf("%d\n", ans.size()); 179 for (auto vv: ans) printf("%d %d\n", vv.first, vv.second); 180 181 182 return 0; 183 }