时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
Two strings u
1 u
2 … u
k and v
1 v
2 … v
l are isomorphic if and only if k = l and there exists a injection g such that u
i = g(v
i) for all i ∈ {1, 2, …, k}.
Note that a function f is injection if and only if f(x) ≠ f(y) for all x ≠ y.
Bobo would like to choose some strings from all n(n +1)/2 substrings of the given string s 1 s 2 … s n.
Find out the maximum number of strings he may choose so that no two chosen strings are isomorphic.
Note that a function f is injection if and only if f(x) ≠ f(y) for all x ≠ y.
Bobo would like to choose some strings from all n(n +1)/2 substrings of the given string s 1 s 2 … s n.
Find out the maximum number of strings he may choose so that no two chosen strings are isomorphic.
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains a string s1, s2, ..., sn.
输出描述:
For each test case, print an integer which denotes the result.
输入例子:
4 abaa 4 abab
输出例子:
6 4
题意 定义两个s1,s2串相似 当且仅当存在一种字母一一对应的映射F 使得s1=F(s2)
现给出一个字符串,有你求一个集合的最大 大小,该集合中的所有子串均不相似。
字符串只包含abc三种字母 长度为5e5
解题思路:
这一题对我来说真的就是神仙题,完全想不到。。。。。
所以根据题解思路走,
题解说的实在太简要,想了好久也只能想明白个大概。。 如果说的不对,那是正常操作。
首先,对于数据范围 字符串最多包含三个字母。
所以考虑枚举映射方案(6种)。
首先考虑合法的情况
将子串按照起始位置和终止位置分类
一种子串符合题目要求的条件是 当且仅当该种子串在6种映射方案中均不相同。
这时候,就会有原串的一种子串6种不同的串
再考虑不合法的情况
如果一种子串存在一种映射 使得它和另一种子串相似。
那么 对于这两种子串,对于每一种映射,都有唯一的一种映射与之相似,那么 这些子串在六种映射中所对应的不同的串合起来也只有六种。( 说不太明白,自己找个例子 推一下就很清楚了)
但这样考虑还是有一个bug,当一个子串全是一种字母的时候,它所映射的不同子串只有3种。
所以 我们枚举玩所有的映射方案后,把他们所有的子串都找出来 就能推出集合最大的大小了。
求子串数目是后缀自动机可以利用后缀自动机在O(n)的时间内解决。
最后答案就是 (不同子串数量 + 3 × 单一字符的串) / 6
只能讲成这样了,这题对我来说难度太高了。。。。。
另外由于多组输入,所以初始化的时候要注意,一不小心就T了。。。。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 2000050
using namespace std;
typedef long long LL;
char s[N];
int ch[N][5],len[N],link[N],rd[N],last,tot,rt,n;
LL F[N],ans[N];
inline void ut(LL &x,LL y) { x = max(x,y); }
int maps[3]={1,2,3};
void add(int pos) {
int x = maps[s[pos] - 'a'] , p = last , np = ++tot;
last = np;
len[np] = len[p] + 1;
F[np] = 1LL;
while (p && !ch[p][x]) ch[p][x] = np , p = link[p];
if (!p)
link[np] = rt;
else {
int q = ch[p][x];
if (len[q] == len[p] + 1)
link[np] = q;
else {
int nq = ++tot;
len[nq] = len[p] + 1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
link[nq] = link[q];
link[q] = link[np] = nq;
while (p && ch[p][x] == q) ch[p][x] = nq , p = link[p];
}
}
return ;
}
void getsize(){
for (int i=1;i<=tot;i++) rd[ link[i] ]++;
queue<int> q;
for (int i=1;i<=tot;i++) {
if (!rd[i]) q.push(i);
ans[i]=0;
}
while (!q.empty()) {
int u = q.front(); q.pop();
F[ link[u] ] += F[u];
if (--rd[ link[u] ] == 0) q.push(link[u]);
ut( ans[ len[u] ] , F[u]);
ans[len[u]]=max(ans[len[u]],F[u]);
}
}
void init(){
rt = last =tot=1;
memset(ch,0,sizeof ch);
//memset(len,0,sizeof len);
memset(rd,0,sizeof rd);
//memset(F,0,sizeof F);
//memset(link,0,sizeof link);
}
int main() {
while(~scanf("%d",&n)){
scanf("%s",s+1);
init();
do{
//printf("%s",s+1);
last=1;
for (int i=1;i<=n;i++) add(i);
}while(next_permutation(maps,maps+3));
getsize();
long long ans=0;
for(int i=1;i<=tot;i++){
ans+=(len[i]-len[link[i]]);
}
int longes=1;
int maxs=1;
for(int i=1;i<=n;i++){
while(i<=n && s[i]==s[i+1]){
i++;
longes++;
}
maxs=max(longes,maxs);
longes=1;
}
cout<<(ans+3*maxs)/6<<endl;
}
return 0;
}