POJ-1743 Musical Theme 哈希

该题题意是给定一个音乐串,要求最长的主题串满足
可以找到两个这样的串,在对方的每一位添加一个数字
两个串互相不能够有重叠

有是多项式插值取模的hash的应用

代码如下:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#define T 99991
#define MAXN 20000
#define MOD 3001
using namespace std;

typedef unsigned long long UInt64;

struct Node
{
    UInt64 key;
    int begin, end, next;
}e[3000000];

int N, seq[MAXN+5], diff[MAXN+5], head[MOD], idx;

UInt64 POW[(MAXN>>1)+5];

void getint(int &t)
{
    char c;
    while (c = getchar(), c < '0' || c > '9');
    t = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') {
        t = t * 10 + c - '0';
    }
}

int Hash(UInt64 key, int begin, int end)
{ // 这里应用贪心思想,如果前面有一个提前完成的主题,一定取前面的主题 
    int Rkey = key % MOD, flag = 0;
    for (int i = head[Rkey]; i != -1; i = e[i].next) {
        if (key == e[i].key) {
            flag = 1;
            if (begin > e[i].end) {
                return true;
            }
        }
    }
    if (!flag) {
        ++idx;
        e[idx].key = key, e[idx].begin = begin;
        e[idx].end = end, e[idx].next = head[Rkey];
        head[Rkey] = idx;
    }
    return false;
} 

bool Accept(int k)
{
    UInt64 key = 0;
    idx = -1;
    memset(head, 0xff, sizeof (head));
    for (int i = 1; i <= k; ++i) {
        key = key * T + diff[i];
    }
    if (Hash(key, 0, k)) {
        return true;
    }
    for (int i = 2; i <= N-k+1; ++i) {
        key -= diff[i-1] * POW[k-1];
        key = key * T + diff[i+k-1];
        if (Hash(key, i-1, i+k-1)) {
            // 这里的begin和end要映射到原数组中
            return true;
        }
    }
    return false;
}

int bsearch(int l, int r)
{
    int mid;
    while (l <= r) {
        mid = (l+r) >> 1;
        if (Accept(mid)) {
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    } 
    return r;
}

int main()
{
    POW[0] = 1;
    int ans; 
    for (int i = 1; i <= 10000; ++i) {
        POW[i] = POW[i-1] * T;
    }
    while (scanf("%d", &N), N) {
        for (int i = 0; i < N; ++i) {
            getint(seq[i]);
        //    scanf("%d", &seq[i]);
        }
        N -= 1;
        for (int i = 1; i <= N; ++i) {
            diff[i] = seq[i] - seq[i-1] + 203;
        }
        if (N >= 9) {
            ans = bsearch(4, N>>1);
            if (ans >= 4) {
                printf("%d\n", ans+1);
            }
            else {
                puts("0");
            }
        }
        else {
            puts("0");
        }
    }
    return 0;    
} 

 

 

posted @ 2012-07-18 23:47  沐阳  阅读(244)  评论(0编辑  收藏  举报