2017北京师范大学ACM校赛 J Just A String (KMP)

题目原文:https://acm.bnu.edu.cn/v3/problem_show.php?pid=52516

解题思路:本题很容易陷入的一个思维误区就是一定要枚举前缀和后缀,这样的话复杂度是O(n^3),肯定会超时的。但其实如果对KMP这个算法理解比较深刻的话,可以发现题目中要求的操作,只需要对KMP算法做一点补充就可以完成。每次枚举一个后缀,作为模板串,当他在原串中匹配的时候,每当有元素匹配的时候就可以很容易的得到A B C的值,而且可以认为包含了所有的情况,不考虑B = 0,因为不影响结果。


心得:当时比赛的时候就没有想到这一点,最开始想用二分+hash做,后来发现这个想法有bug,还是对kmp的理解不够深刻,如果再做出这道题就可以进前6了。


AC代码:

/*
    @Author: wchhlbt
    @Date:   2017/4/26
*/
#include <bits/stdc++.h>

#define Fori(x) for(int i=0;i<x;i++)
#define Forj(x) for(int j=0;j<x;j++)
#define maxn 50005
#define inf 0x3f3f3f3f
#define ONES(x) __builtin_popcount(x)
using namespace std;

typedef long long ll ;
const double eps =1e-8;
const int mod = 1000000007;
typedef pair<int, int> P;
const double PI = acos(-1.0);
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

ll ans;

int f[maxn];//失配函数

void getFail(string &p)
{
    int plen = p.length();
    f[0] = 0; f[1] = 0;
    for(int i = 1; i<plen; i++){
        int j = f[i];
        while(j && p[i]!=p[j])  j = f[j];
        f[i+1] = (p[i]==p[j]) ? j+1 : 0;
    }
}
int find(string &s, string &p)//s->待匹配文本串  p->模板串
{
    int slen = s.length();
    int plen = p.length();
    getFail(p);
    int j = 0;
    int cnt = 0;
    for(int i = 0; i<slen; i++){
        while(j && s[i]!=p[j])  j = f[j];
        if(s[i]==p[j]){
            int len = j+1;//只需要补充这三行
            ll A = i+1-len; ll B = len; ll C = plen - len;
            ans ^= A*B*B*C;
            j++;
        }
        if(j==plen){
            j = f[j];//不考虑重叠时,此处置0
            //return i + 1 -plen; 返回第一个匹配的位置
            cnt++;
        }
    }
    return cnt;
}

int main()
{
    //freopen("test.txt","r",stdin);
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        cin>>s;
        ans = 0;
        int len = s.length();
        for(int i = 0; i<len; i++){
            string tmp = s.substr(i);
            getFail(tmp);
            find(s,tmp);
        }
        cout << ans << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值