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 }

 

posted @ 2018-04-04 12:09  lzw4896s  阅读(293)  评论(0编辑  收藏  举报