kmp

题意:

图片说明

分析:

这一题,我最初很没思路。刚开始想会不会是kmp扩展,但是琢磨一番发现无法解决。
然后,在进行手工推算时,发现这是个kmp问题。

请看:
题目让我们求的是:
对于字符串s,判断他的每一个前缀和每一个后缀的B
是否?

从题目所给的数据量来看,我们很简单就能想到枚举。
但是,即便枚举我们也只能承受n^2级别的。
即,我们可以枚举每一个后缀去和每一个前缀进行比较,判断。
这个比较判断的时间,至关重要。我们应该使其尽量的短。

接下来我们看看,如何进行判断的:
图片说明
s1表前缀,s2表后缀。
我们看:如果此时s1的2,3,4与s2的1,2,3匹配。他们为最大匹配。
那么,当我们的前缀再往后进一格呢?
图片说明
这时,需要分类讨论了:
1.如果s1的5与s2的4匹配,那么此时的最大匹配就是4即B就为4
这是一定的,因为倘若有一个更大的匹配,比如1,2,3,4,5那么在上一次匹配中2,3,4就不是最大匹配了!
2,如果s1的5和s2的4不匹配呢?
我们想想,在最终匹配的B中s1的5是一定要匹配上的。因为他在终点!
又,基于上面1的证明,是不可能再比上一次的匹配大了。
所以我们要对s2的4往前找。
假设我们找到了3那么判断3是否为s1的5时,我们一定要保证s2的1,2等于s1的3,4
而s1的3,4等于s2的2,3.
有没有感到一丝丝熟悉?这不就是我们求解kmp的next[]的操作嘛!!
即,一旦发现比较处不是s1的5我们就让j=net[j]跳到下一个比较的位置。
一旦有一个==那么此地就是最大匹配
当j==-1时,意味没有一个为5B为空的

3.也是基于2的一个特殊情况
如果我们s2都匹配完了,但是s1还在增加该怎么办?
即:
图片说明
假设s1(1,2,3,4,5)==s2(1,2,3,4,5)
然后此时要匹配s1[6]
我们该怎么办?
直接让j=net[j]就好了。(并不难理解,认清问题,画画图)

代码如下:

#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int max_n = 2100;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while (!isdigit(c)) { if (c == '-')f = -1;c = getchar(); }
    while (isdigit(c))x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x * f;
}

inline string readstring()
{
    char ch = getchar();
    string st1 = "";
    while (!((ch >= 'a') && (ch <= 'z')))
        ch = getchar();
    while (((ch >= 'a') && (ch <= 'z')))
        st1 += ch, ch = getchar();
    return st1;
}
inline void write(ll x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
    return;
}
inline void copy(string& s, string& p) {
    p.clear();
    for (register int i = 0;i < s.size();++i)p += s[i];
}
int net[max_n];
inline void getnext(string& p) {
    register int i = 0;register int j = -1;
    net[0] = -1;
    while (i < p.size()) {
        if (j == -1 || p[i] == p[j])net[++i] = ++j;
        else j = net[j];
    }
}
int main() {
    int T = read();
    register string s;
    register string p;
    while (T--) {
        register ll ans = 1;
        s = readstring();
        copy(s, p);
        for (int i = 0;i < p.size();++i) {
            string behind = p.substr(i);
            register int pos = 0;getnext(behind);
            for (register int j = 0;j < s.size();++j) {
                while (true) {
                    if (pos == behind.size())
                        pos = net[pos];
                    if (pos == -1 || s[j] == behind[pos]) {
                        ++pos;
                        break;
                    }
                    else pos = net[pos];
                }
                int B = pos;
                int A = j + 1 - B;
                int C = behind.size() - B;
                ll res = (ll)A * B * B * C;
                ans = ans ^ res;
            }
        }write(ans ^ 1);putchar('\n');
    }
}