codeforces 123 D. String (后缀数组+两次二分得到区间+rmq)
题意:定义一个函数F..
For exampe: _F_(_babbabbababbab_, _babb_) = 6. The list of pairs is as follows:(1, 4), (4, 7), (9, 12)
Its continuous sequences are:
*
(1, 4)
*
(4, 7)
*
(9, 12)
*
(1, 4), (4, 7)
*
(4, 7), (9, 12)
*
(1, 4), (4, 7), (9, 12)
erfen
. erfen 题目描述得很烂..看例子把..大概就是:如果字符串y在字符串x中出现n次,那么F(x,y)=n*(n+1)/2
现在给一个字符串,求所有的F(s,x)的和,x为字符串的所有不相同的子串.
思路:由于刚刚写了一个求一个字符串所有不同子串个数的题目...于是就想到了后缀数组...
写完之后观察height[i].如果把height[i]看成底在x轴上的第i个矩形的高的话,n就是一段连续的矩形的长度.
然后...暴力会tle 48
题解说单调栈...但是单调栈之后还要线段树or并查集? (by 羊神)
...不会啊orz
最后用了二分+rmp过掉的
大概就是两次二分得到一个矩形的区间,和whust2016 #1的那道题有点像.
/* ***********************************************
Author :111qqz
Created Time :2016年08月01日 星期一 04时57分01秒
File Name :code/cf/problem/123d.cpp
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
#define fst first
#define sec second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ms(a,x) memset(a,x,sizeof(a))
typedef long long LL;
#define pi pair < int ,int >
#define MP make_pair
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
const int N=1E5+7;
int n,sa[N],rk[N],t[N],t2[N],cnt[N];
int height[N];
char s[N];
int cmp( int *r , int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void getSa( int n,int m)
{
int *x = t;
int *y = t2;
ms(cnt,0);
for ( int i = 0 ; i < n ; i++) cnt[x[i]=s[i]]++;
for ( int i = 1 ; i < m ; i++) cnt[i] +=cnt[i-1];
for ( int i = n-1 ; i >= 0 ; i--) sa[--cnt[x[i]]] = i ;
for ( int k = 1 ; k <= n ; k <<=1)
{
int p = 0 ;
for ( int i = n-k ; i < n; i++) y[p++] = i;
for ( int i = 0 ; i < n ; i++) if (sa[i]>=k) y[p++] = sa[i]-k;
ms(cnt,0);
for ( int i = 0 ; i <n ; i++) cnt[x[y[i]]]++;
for ( int i = 0 ; i < m ; i++) cnt[i] +=cnt[i-1];
for ( int i = n-1 ; i >= 0 ; i--) sa[--cnt[x[y[i]]]] = y[i];
swap(x,y);
p = 1;
x[sa[0]] = 0 ;
for ( int i = 1 ;i <n ; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k)?p-1:p++;
if (p>=n) break;
m = p;
}
}
void getHeight( int n)
{
int k = 0 ;
for ( int i = 0 ; i < n ; i++) rk[sa[i]] = i ;
height[0] = 0 ;
for ( int i = 0 ; i < n ; i++)
{
if (rk[i]==0) continue;
if (k) k--;
int j = sa[rk[i]-1];
while (s[i+k]==s[j+k]) k++;
height[rk[i]] = k;
}
}
int getSuffix( char s[])
{
int len = strlen(s);
int up = 0 ;
for ( int i = 0 ; i < len ; i++)
{
int val = s[i];
up = max(up,val);
}
s[len++]='$';
getSa(len,up+1);
getHeight(len);
return len;
}
LL cal( LL x)
{
return x*(x+1)/2LL;
}
LL solve2(int n)
{
for ( int i = 0 ; i < n ; i++) cout<<i<<" "<<height[i]<<endl;
ms(cnt,0);
int up = 0 ;
for ( int i = 1 ; i < n; i++) cnt[height[i]]++,up=max(up,height[i]);
for ( int i = up-1 ; i >= 0 ; i--) cnt[i] = cnt[i]+cnt[i+1];
LL res = 0LL ;
for ( int i = 0 ; i <= up ; i++)
res = res + cal(1LL*cnt[i]);
return res;
}
/*
stack<int>stk;
int l[N],r[N];
bool visl[N],visr[N];
LL solve ( LL n) //单调栈
{
LL res = n*(n-1LL)/2LL;
int up = 0 ;abaabaabaaba
for ( int i = 1 ; i < n; i++) up = max(height[i],up);
// for ( int i = 1 ; i <= n ; i++) cout<<"i:"<<i<<" height[i]:"<<height[i]<<endl;
height[0] = -1;
height[n+1] = -1 ; //单调队列的哨兵
stk.push(0);
int x;
for ( int i = 1 ; i <= n; i++)
{
for (x=stk.top();height[x]>=height[i];x=stk.top()) stk.pop();
l[i] = x+1;
stk.push(i);
// cout<<"i:"<<i<<endl;
}
while (!stk.empty()) stk.pop() ; stk.push(n+1);
for ( int i = n ; i >=1 ; i--)
{
for (x=stk.top() ; height[x]>=height[i] ; x = stk.top()) stk.pop();
r[i] = x-1;
stk.push(i);
}
// for ( int i = 1 ; i <= n ; i++)
// cout<<"i:"<<i<<" l[i]:"<<l[i]<<" r[i]:"<<r[i]<<" height[i]:"<<height[i]<<" "<<(r[i]-l[i]+1)*height[i]<<endl;
// int mxh = 0 ;
ms(visl,false);
ms(visr,false);
int mxh = 0 ;
int more =1;
for ( int i = 1 ;i <= n ; i++)
{
if (height[i]==0)
{
mxh = 0 ;
continue;
}
if (visr[r[i]]&&visl[l[i]])
{
mxh = 0 ;
continue;
}
if (i>1&&height[i-1]<height[i]) more = height[i]-height[i-1];
if (i<n&&height[i+1]<height[i]) more = min(more,height[i]-height[i+1]);
res = res + cal((r[i]-l[i]+1))*(more);
mxh = max(mxh,height[i]);
visr[r[i]] = true;
visl[l[i]] = true;
// cout<<"i:"<<i<<" res:"<<res<<endl;
}
return res;
} */
int dp[N][30]; // for rmq;
void rmq_init( int n)
{
for ( int i = 1 ; i <= n ; i++) dp[i][0] = height[i];
for ( int j = 1 ; (1<<j) <= n ; j++)
for ( int i = 1 ; i + (1<<j) - 1 <= n ; i++)
dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq( int l,int r)
{
if (l>r) swap(l,r);
int k = 0 ;
while (1<<(k+1)<=r-l+1) k++;
int res = min(dp[l][k],dp[r-(1<<k)+1][k]);
return res;
}
LL solve( LL len)
{
rmq_init(len);
LL ans = len*(len+1)/2;
// for ( int i = 1 ; i <= len ; i++) cout<<i<<" :"<<height[i]<<endl;
for ( int i = 1 ; i <= len ; i++)
{
int l = 0 ,r = i ;
while (r>l+1)
{
int mid = (l+r)/2;
if (rmq(mid,i-1)>=height[i]) r = mid;
else l = mid;
}
int L = i,R= len+1;
while (R>L+1)
{
int mid = (L+R) / 2;
if (rmq(i+1,mid)>height[i]) L = mid;
else R = mid;
}
// cout<<"i:"<<height[i]<<"L:"<<L<<" r:"<<r<<" ans:"<<ans<<endl;
ans +=1LL*height[i]*(L-i+1)*(i-r+1);
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("code/in.txt","r",stdin);
#endif
scanf("%s",s);
int len = getSuffix(s);
// cout<<"len:"<<len-1<<endl;
LL ans = solve(len-1);
printf("%lld\n",ans);
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}