[UVa 12338] Anti-Rhyme Pairs (字符串哈希+二分)

链接

UVA 12338


题意

对每个case,给出N个单词(字符串),之后有Q组询问,对每组询问(i, j),给出第i个字符串和第j个字符串的最长公共前缀长度。


思路

这是一个典型的字符串哈希问题。字符串有很好的单调性,可以使其在匹配问题上结合二分提高效率。比如本问题,找两个字符串最长公共前缀,如果前缀j匹配,那么前缀i(i < j)一定是匹配的,利用二分能很快找到最长匹配的长度。
本题做法是对每个字符串求其前缀hash数组,对每个询问二分查找即可。
代码用了自然溢出哈希,但是没有被卡掉。


代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
using namespace std;
typedef unsigned long long ulint;
#define maxn (1000007)
const ulint seed = 30007uLL;
const ulint mod = 1e9 + 1017uLL;
ulint Hi[maxn], Hj[maxn];

string word[maxn];
vector<ulint> H[maxn];

int solve(int i, int j)
{
    int ans = 0, l = 1, r = min(word[i].size(), word[j].size()), m;
    vector<ulint> &hi = H[i];
    vector<ulint> &hj = H[j];

    while(l <= r)
    {
        m = (l + r) >> 1;

        if(hi[m-1] == hj[m-1])
        {
            ans = m;
            l = m + 1;
        }
        else r = m - 1;
    }

    return ans;
}

int main()
{
    //freopen("12338.txt", "r", stdin);

    cin.sync_with_stdio(false);

    int T, kase = 0;
    cin >> T;
    while(T--)
    {
        printf("Case %d:\n", ++kase);

        int N;
        cin >> N;
        for(int i = 1; i <= N; i++)
        {
            cin >> word[i];
            string& s = word[i];
            vector<ulint>& h = H[i];
            h.clear();
            h.push_back(s[0] - 'a' + 1);
            for(int j = 1; j < s.size(); j++)
            {
                h.push_back(h[j-1] * seed + s[j] - 'a' + 1);
            }
        }

        int Q, i, j;
        cin >> Q;
        while(Q--)
        {
            cin >> i >> j;
            printf("%d\n", solve(i, j));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值