3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3425 Solved: 1559
[ Submit][ Status][ Discuss]
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
Source
这题很尬。。。。。。
我能说我是看错题目才想到这种做法的吗。。?
首先对于那个和式,很容易发现和按sa数组下标的顺序算的答案是一样的
因为把两个式子乘二都等于算所有( i , j )有序対的差异
于是。。我们可以用后缀数组瞎搞。。。
建一下后缀数组,然后从后往前做,维护height的最小值的和即可
单调栈就可以了。。。然而蒟蒻很蠢居然还上了一棵线段树。。。。。。
PS.听说出题的目的是考后缀自动机。。?
代码:
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int INF = 2147483647;
const int maxn = 500100;
const int maxseg = 4 * maxn;
int m;
char s[maxn];
int rank[maxn],t1[maxn],t2[maxn],c[maxn];
LL siz[maxseg],sum[maxseg],ans,n,sa[maxn],sumtj,height[maxn];
bool flag[maxseg];
inline void del(int o)
{
flag[o] = 1; siz[o] = sum[o] = 0;
}
inline void pushdown(int o)
{
if (flag[o])
{
int lc = o * 2,rc = o * 2 + 1;
del(lc); del(rc);
flag[o] = 0;
}
}
inline void maintain(int o)
{
int lc = o * 2,rc = o * 2 + 1;
siz[o] = siz[lc] + siz[rc];
sum[o] = sum[lc] + sum[rc];
}
inline void reset(int o,int l,int r,int al,int ar)
{
if (al <= l && r <= ar){del(o); return;}
pushdown(o);
int lc = o * 2,rc = o * 2 + 1,mid = l + r >> 1;
if (ar <= mid) reset(lc,l,mid,al,ar);
if (mid < al) reset(rc,mid + 1,r,al,ar);
if (al <= mid && mid < ar)
{
reset(lc,l,mid,al,mid);
reset(rc,mid + 1,r,mid + 1,ar);
}
maintain(o);
}
inline LL query(int o,int l,int r,int al,int ar)
{
if (al <= l && r <= ar) return siz[o];
pushdown(o);
int lc = o * 2,rc = o * 2 + 1,mid = l + r >> 1;
if (ar <= mid) return query(lc,l,mid,al,ar);
if (mid < al) return query(rc,mid + 1,r,al,ar);
if (al <= mid && mid < ar) return query(lc,l,mid,al,mid) + query(rc,mid + 1,r,mid + 1,ar);
}
inline void inc(int o,int l,int r,int pos,LL cnt)
{
if (l == r){sum[o] += cnt * l; siz[o] += cnt; return;}
pushdown(o);
int mid = l + r >> 1,lc = o * 2,rc = o * 2 + 1;
if (pos <= mid) inc(lc,l,mid,pos,cnt);
else inc(rc,mid + 1,r,pos,cnt);
maintain(o);
}
inline void build()
{
int *x = t1,*y = t2;
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) c[x[i] = s[i]]++;
for (int i = 1; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
for (int i = n - k + 1; i <= n; i++) y[++p] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++p] = sa[i] - k;
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) c[x[y[i]]]++;
for (int i = 1; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
swap(x,y);
x[sa[1]] = p = 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;
if (p >= n) break;
m = p;
}
for (int i = 1; i <= n; i++) rank[sa[i]] = i;
int k = 0;
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;
}
}
int main()
{
#ifdef dyf
freopen("hyj1.txt","r",stdin);
freopen("hyj2.txt","w",stdout);
#endif
scanf("%s",s + 1); n = strlen(s + 1);
for (int i = 1; i <= n; i++) m = max(m,(int)s[i]);
build();
ans = 0;
for (LL i = n - 1; i >= 1; i--)
{
sumtj += n - sa[i + 1] + 1;
ans += (n - sa[i] + 1) * (n - i) + sumtj;
LL k = query(1,0,n,height[i + 1] + 1,n);
reset(1,0,n,height[i + 1] + 1,n);
inc(1,0,n,height[i + 1],k + 1);
ans -= 2 * sum[1];
}
printf("%lld",ans);
return 0;
}