4650: [Noi2016]优秀的拆分

4650: [Noi2016]优秀的拆分

Time Limit: 30 Sec   Memory Limit: 512 MB
Submit: 192   Solved: 117
[ Submit][ Status][ Discuss]

Description

如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆
分是优秀的。例如,对于字符串 aabaabaa,如果令 A=aabA=aab,B=aB=a,我们就找到了这个字符串拆分成 AABBA
ABB 的一种方式。一个字符串可能没有优秀的拆分,也可能存在不止一种优秀的拆分。比如我们令 A=aA=a,B=baa
B=baa,也可以用 AABBAABB 表示出上述字符串;但是,字符串 abaabaa 就没有优秀的拆分。现在给出一个长度为
 nn 的字符串 SS,我们需要求出,在它所有子串的所有拆分方式中,优秀拆分的总个数。这里的子串是指字符串
中连续的一段。
以下事项需要注意:
出现在不同位置的相同子串,我们认为是不同的子串,它们的优秀拆分均会被记入答案。在一个拆分中,允许出现
 A=BA=B。例如 cccc 存在拆分 A=B=cA=B=c。字符串本身也是它的一个子串。

Input

每个输入文件包含多组数据。输入文件的第一行只有一个整数 TT,表示数据的组数。保证 1≤T≤10。接
下来 TT 行,每行包含一个仅由英文小写字母构成的字符串 SS,意义如题所述。N<= 30000

Output

输出 TT 行,每行包含一个整数,表示字符串 SS 所有子串的所有拆分中,总共有多少个是优秀的拆分。

Sample Input

4
aabbbb
cccccc
aabaabaabaa
bbaabaababaaba

Sample Output

3
5
4
7
explanation
我们用 S[i,j]S[i,j] 表示字符串 SS 第 ii 个字符到第 jj 个字符的子串(从 11 开始计数)。
第一组数据中,共有 33 个子串存在优秀的拆分:
S[1,4]=aabbS[1,4]=aabb,优秀的拆分为 A=aA=a,B=bB=b;
S[3,6]=bbbbS[3,6]=bbbb,优秀的拆分为 A=bA=b,B=bB=b;
S[1,6]=aabbbbS[1,6]=aabbbb,优秀的拆分为 A=aA=a,B=bbB=bb。
而剩下的子串不存在优秀的拆分,所以第一组数据的答案是 33。
第二组数据中,有两类,总共 44 个子串存在优秀的拆分:
对于子串 S[1,4]=S[2,5]=S[3,6]=ccccS[1,4]=S[2,5]=S[3,6]=cccc,它们优秀的拆分相同,均为 A=cA=c,B=cB=c,但由于这些子串位置不同,因此要计算 33 次;
对于子串 S[1,6]=ccccccS[1,6]=cccccc,它优秀的拆分有 22 种:A=cA=c,B=ccB=cc 和 A=ccA=cc,B=cB=c,它们是相同子串的不同拆分,也都要计入答案。
所以第二组数据的答案是 3+2=53+2=5。
第三组数据中,S[1,8]S[1,8] 和 S[4,11]S[4,11] 各有 22 种优秀的拆分,其中 S[1,8]S[1,8] 是问题描述中的例子,所以答案是 2+2=42+2=4。
第四组数据中,S[1,4]S[1,4],S[6,11]S[6,11],S[7,12]S[7,12],S[2,11]S[2,11],S[1,8]S[1,8] 各有 11 种优秀的拆分,S[3,14]S[3,14] 有 22 种优秀的拆分,所以答案是 5+2=75+2=7。

HINT

Source

[ Submit][ Status][ Discuss]

NOI2016D1T1...
其实这道题有95分部分分。。。而且相当好写(O(n^2logn))
写下正解做法。。。。
令f[i]:以i结尾的,形式如AA的字符串的组数
令g[i]:以i开头的,形式如AA的字符串的组数
若能预处理好f、g数组,那么答案就是∑f[i]g[i+1]
枚举字符串A的长度为L,在母串中每隔L个位置就设置一个关键点
由于AA的长度为2L,所以此时所有形式如AA的字符串都会经过且恰好经过两个关键点
对于原串的正串和反串都预处理出SA
每次枚举一个L,然后枚举相邻的两个关键点,求出它们的lcs和lcp
画出来大概这样4650: [Noi2016]优秀的拆分_第1张图片
考虑相邻的两个关键位置x,y,lcs是从a,b开始的串
那么a+L-1和b+L-1是同构的,以及a+L和b+L是同构的...
讨论一下,就是一段连续的f和一段连续的g都加一
差分一下作前缀和即可
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
const int maxn = 3E4 + 30;
const int T = 15;
typedef long long LL;
 
int n,TT,c[maxn],t1[maxn],t2[maxn],s1[maxn],s2[maxn],r1[maxn],r2[maxn]
    ,h1[maxn],h2[maxn],f[maxn],g[maxn],len[maxn],bin[maxn],m1[maxn][T],m2[maxn][T];
char A[maxn],B[maxn]; LL Ans;
 
void Work(int m,char *s,int *sa,int *rank,int *height)
{
    memset(t1,0,sizeof(t1)); memset(t2,0,sizeof(t2));
    memset(c,0,sizeof(c)); int *x = t1,*y = t2;
    for (int i = 1; i <= n; i++) ++c[x[i] = s[i] - 'a' + 1];
    for (int i = 2; i <= m; i++) c[i] += c[i - 1];
    for (int i = 1; i <= n; i++) sa[c[x[i]]--] = i;
    for (int k = 1; k <= n; k <<= 1)
    {
        int p = 0;
        for (int i = n; i > n - k; i--) y[++p] = i;
        for (int i = 1; i <= n; i++) if (sa[i] - k > 0) y[++p] = sa[i] - k;
        for (int i = 1; i <= m; i++) c[i] = 0;
        for (int i = 1; i <= n; i++) ++c[x[i]];
        for (int i = 2; i <= m; i++) c[i] += c[i - 1];
        for (int i = n; i; i--) sa[c[x[y[i]]]--] = y[i];
        swap(x,y); p = x[sa[1]] = 1;
        for (int i = 2; i <= n; i++)
            x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i] + k] == y[sa[i-1] + k] ? p : ++p;
        m = p; if (m == n) break;
    }
     
    int k = 0;
    for (int i = 1; i <= n; i++) rank[sa[i]] = i;
    for (int i = 1; i <= n; i++)
    {
        if (k) --k;
        int j = sa[rank[i] - 1];
        while (s[i + k] == s[j + k]) ++k;
        height[rank[i]] = k;
    }
}
 
void Rmq_Pre()
{
    for (int i = 1; i <= n; i++)
        m1[i][0] = h1[i],m2[i][0] = h2[i];
    for (int i = 1; i < T; i++)
        for (int j = 1; j <= n; j++)
        {
            int Nex = j + (1 << i - 1);
            if (Nex > n) break;
            m1[j][i] = min(m1[j][i-1],m1[Nex][i-1]);
            m2[j][i] = min(m2[j][i-1],m2[Nex][i-1]);
        }
}
 
int lcs(int x,int y)
{
    x = n - x + 1; y = n - y + 1;
    x = r2[x]; y = r2[y]; if (x > y) swap(x,y);
    ++x; int k = y - x + 1;
    return min(m2[x][bin[k]],m2[y - len[k] + 1][bin[k]]);
}
 
int lcp(int x,int y)
{
    x = r1[x]; y = r1[y]; if (x > y) swap(x,y);
    ++x; int k = y - x + 1;
    return min(m1[x][bin[k]],m1[y - len[k] + 1][bin[k]]);
}
 
void Solve()
{
    scanf("%s",A + 1); n = strlen(A + 1);
    for (int i = 1; i <= n; i++) B[i] = A[n - i + 1];
    Work(26,A,s1,r1,h1); Work(26,B,s2,r2,h2); Rmq_Pre();
    for (int L = 1; L <= n / 2; L++)
        for (int i = L,j = i + L; i <= n; i += L,j += L)
        {
            int x = min(lcs(i,j),L),y = min(lcp(i,j),L);
            if (x + y - 1 < L) continue;
            ++g[i - x + 1]; --g[i + y - L + 1];
            ++f[j - x + L]; --f[j + y];
        }
    for (int i = 1; i <= n; i++) f[i] += f[i - 1],g[i] += g[i - 1];
    for (int i = 1; i < n; i++) Ans += 1LL * f[i] * g[i + 1];
    cout << Ans << endl; Ans = 0;
    memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
    memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2));
    memset(r1,0,sizeof(r1)); memset(r2,0,sizeof(r2));
    memset(h1,0,sizeof(h1)); memset(h2,0,sizeof(h2));
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    for (int i = 1; i < maxn; i++)
    {
        bin[i] = (1 << bin[i-1] + 1) < i ? bin[i-1] + 1 : bin[i-1];
        len[i] = (1 << bin[i]);
    }
    cin >> TT; while (TT--) Solve();
    return 0;
}

你可能感兴趣的:(后缀数组)