4516: [Sdoi2016]生成魔咒
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1362 Solved: 766
[ Submit][ Status][ Discuss]
Description
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
需要求出,当前的魔咒串 S 共有多少种生成魔咒。
Input
第一行一个整数 n。
第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9
Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
7
1 2 3 3 3 1 2
1 2 3 3 3 1 2
Sample Output
1
3
6
9
12
17
22
3
6
9
12
17
22
HINT
Source
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
const int INF = 2147483647;
const int maxn = 100100;
int a[maxn];
map<int,int> ch[maxn * 2];
int f[maxn * 2],Max[maxn * 2],dp[maxn * 2],cnt[2 * maxn],tot = 1,last = 1;
LL n,ans;
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline LL cal(int u)
{
return Max[u] - Max[f[u]];
}
inline void insert(int c)
{
int v = last;
Max[last = ++tot] = Max[v] + 1; f[last] = 1;
while (v && !ch[v][c]) ch[v][c] = last , v = f[v];
if (!v) {ans += cal(last); return;}
int p = ch[v][c];
if (Max[p] != Max[v] + 1)
{
int np = ++tot;
Max[np] = Max[v] + 1;
f[np] = f[p]; ans += cal(np);
ans -= cal(p); f[p] = np; ans += cal(p);
f[last] = np;
while (v && ch[v][c] == p) ch[v][c] = np , v = f[v];
ch[np] = ch[p];
}
else f[last] = p;
ans += cal(last);
}
int main()
{
n = getint();
for (int i = 1; i <= n; i++) a[i] = getint();
for (int i = 1; i <= n; i++) insert(a[i]) , printf("%lld\n",ans);
return 0;
}