zoukankan      html  css  js  c++  java
  • 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 eq 0$,因为p是质数,所以$A * x_i  eq 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 = sumlimits_{i=0}^{n - 1}x_i$,  $sy = sumlimits_{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
    ", ans.size());
    179     for (auto vv: ans) printf("%d %d
    ", vv.first, vv.second);
    180     
    181     
    182     return 0;
    183 }
  • 相关阅读:
    Mono项目将继续推动基于Linux的开发
    VS.PHP 在Visual Studio 下的 PHP 开发 IDE 工具
    SQL Server 2008 的代码提示功能
    想做的时候没有机会了
    我的最爱
    双缓冲
    做个好男人!
    再见了,曾经喜欢过的歌手
    看看他是喜欢你还是爱你的~~~
    独家:未来五年程序员应当具备的十项技能
  • 原文地址:https://www.cnblogs.com/vb4896/p/8716367.html
Copyright © 2011-2022 走看看