WHU 1583 Palindrome(回文树)

题意:把一个串分成2部分,求左半部份的本质不同回文串个数等于右半部份本质不同回文串个数的2倍的所有位置乘起来的答案。

做法:学习了下回文树,总结几点。

1.用编号去代表每个不同的回文串。比如编号为5的回文串为aba,那么next[5]['z']就是zabaz。next[i][j]保存的是这个在编号为i回文串的两端加字母j的回文串的编号。

2.fail[i]代表编号为i的回文串的包含在内具有相同右端点的最长回文串。。例如ababa,下一个是aba,再下一个是a。

3.类似ac自动机的失配做法。通过fail尝试所有以前一个字母为右端点的回文串,例如长度是L,那么就判断当前位置pos-1-L是否与pos字母相同。相同就匹配成功。不相同就继续fail,匹配成功即是以当前位置为右端点的最长的回文串。

4.在求出最长回文串后得看看是否是新的,那么这个就要利用到next,例如当前字母为a,匹配成功的前一个回文串编号为last,那么就要看next[last]['a']是否不为0,为0说明当前串是新串(那么就要加入),反之就是已经出现过。

5.如果是新串就需要求fail指针,是为了后面一个加入字母的匹配。我们继续类似3的方法,继续fail[last],求是否匹配。即求下一个以当前位置为右端点的回文串。注意这里找到的回文串必定已经出现过了。因为当前的串为回文串,那么找到的通过对称可以发觉左边已经出现过了。所以可以用fail[i] = next[last][a]。

6.需要设定边界。即偶数边界和奇数边界,偶数边界的len为0,奇数边界的len为-1,这都是因为pos-1-L所决定的。偶数边界就是与前一个比较,奇数边界就是与自己比较(必定能匹配啦)。

网上对比了一些代码。删去了一些无用的语句。感觉比较简洁易懂了。

AC代码:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define eps 1e-8
#define MAXN 100000+100
#define MOD 1000000007
#define palin(x, id, c) (s[id - 1 - l[x]] - 'a' == c)

char str[MAXN],str2[MAXN];
struct PalindromeTree
{
    int sz, odd_, even, last;
    int next[MAXN][26], fail[MAXN], l[MAXN];
    void Init(char *s)
    {
        sz = 0;
        odd_ = ++sz, l[odd_] = -1, fail[odd_] = odd_;
        memset(next[sz],0,sizeof(next[sz]));
        even = ++sz, l[even] =  0, fail[even] = odd_;
        memset(next[sz],0,sizeof(next[sz]));
        last = odd_;
        s[0] = '$';
    }
    void Add(int c, int id, char *s)
    {
        while(!palin(last, id, c)) last = fail[last];
        if (next[last][c]) last = next[last][c];
        else
        {
            int x = last;
            ++sz;
            memset(next[sz],0,sizeof(next[sz]));
            next[x][c] = sz, l[sz] = l[x] + 2;
            if (x == odd_) fail[sz] = even;
            else
            {
                x = fail[x];
                while(!palin(x, id, c)) x = fail[x];
                fail[sz] = next[x][c];
            }
            last = sz;
        }
    }
}pt;
int ans1[MAXN],ans2[MAXN];
int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o.txt","w",stdout);
#endif
    int cas = 1,t;
    scanf("%d\n",&t);
    while(t--)
    {
        gets(str+1);
        pt.Init(str);
        int len = strlen(str+1);
        for(int i = 1; i <= len; i++)
        {
            pt.Add(str[i] - 'a', i, str);
            ans1[i] = pt.sz-2;
            str2[len-i+1] = str[i];
        }
        pt.Init(str2);
        for(int i = 1; i <= len; i++)
        {
            pt.Add(str2[i] - 'a', i, str2);
            ans2[len-i+1] = pt.sz-2;
        }
        ll ret = 1;
        for(int i = 1; i <= len-1; i++)
        {
//            cout<<i<<" "<<ans1[i]<<" "<<ans2[i+1]<<endl;
            if(ans1[i] == ans2[i+1]*2) ret = ret*(ll)i%MOD;
        }
        if(ret == 1) ret = 0;
        printf("%lld\n",ret);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
whu-river数据集是一个用于河流水质监测和预测的数据集。该数据集由华中科技大学收集和创建,旨在帮助研究人员和决策者更好地理解和管理河流的水质问题。 该数据集包含了来自中国不同河流的水质监测数据,包括河水的化学指标、生物学指标、水文学指标和气象指标等。这些指标可以帮助评估河流的污染程度和水质状况,并提供对河流水质变化的预测。数据集中的每个样本都包含了特定时间点对应的水质指标数值。 使用whu-river数据集,研究人员可以进行水质分析、趋势预测和模型构建等工作。例如,可以通过分析数据集中的化学指标,了解河流中各种物质的含量和分布情况,进而评估河流的水质状况。同时,还可以利用数据集中的生物学指标,评估河流的生态系统健康度。 此外,whu-river数据集还可以用于建立水质预测模型。通过对历史数据的分析和挖掘,可以发现不同指标之间的关联性和规律,从而构建出准确预测水质的模型。这样的模型可以对未来水质状况进行预测,为决策者提供科学依据,制定更为有效的水资源管理和保护措施。 总之,whu-river数据集是一个宝贵的资源,对于研究河流水质和水资源管理具有重要意义。它提供了丰富的水质监测数据,可用于水质分析、趋势预测和模型构建等工作,为保护水环境和维护水质做出贡献。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值