关闭

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

标签: uva哈希字符串二分
117人阅读 评论(0) 收藏 举报

链接

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;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7383次
    • 积分:667
    • 等级:
    • 排名:千里之外
    • 原创:63篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条