两道(疑似)哈希的题

2018.2.5 新生训练Week3 E.密码碰撞


EOJ 的登录系统爆出了一个重大问题,当正确的密码是你输入的密码的子串时,就可以成功登录!

例如你的密码是 abc,则你输入 abcc,aabc,甚至 dfjklsdfabcsdjfkl,都可以成功登录!

出现了这么大的问题,那就一定要有人来背锅,管理员们希望在背锅之前先衡量一下锅的大小。

现在有一份 EOJ 用户的密码表,里面包含了 n 个用户的密码,第 i 个用户的密码是 pwdi。我们定义锅的大小为所有有序对 (i,j) (i≠j) 的数量,使得用户 i 能够输入他的密码 pwdi 成功登陆用户 j 的账户。

换句话说,我们现在需要知道,有多少有序对 (i,j) (i≠j) 使得 pwdj 是 pwdi 的子串。

第 1 行包含一个整数 n,1≤n≤20 000,表示密码表中密码的数量。
第 1+i (1≤i≤n) 行包含一个长度不超过 10 且由小写字母组成的字符串,表示 pwdi。

说明


因为长度太短了,所以可以直接枚举子串(每个密码最多55个子串),hash一下存进map里统计子串的出现次数。然后对于每个密码,计算其在子串中出现的次数。记得要减去n,因为每个密码也一定是自己的子串。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 20005;
typedef long long ll;
ll SS[maxn];
set<ll> S[maxn];
map<ll, int> m;
char s[15];
int n, ans, len;

int main()
{
    cin >> n;
    for (int i = 0; i < n; ++i)
    {
        scanf("%s", s);
        len = strlen(s);
        for (int j = 0; j < len; ++j)
        {
            ll h = 0;
            for (int k = j; k < len; ++k)
            {
                h = h * 29 + s[k]-'a'+1;
                S[i].insert(h);
                if (!j && k+1 == len) SS[i] = h;
            }
        }
        for (auto x: S[i]) ++m[x];
    }
    for (int i = 0<
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值