題目鏈結
對於原串的每個字首,求有多少個不同的子串.
對於長度為n
nn 的串,子串個數為 n∗(
n−1)
2−∑i
=1nh
eigh
t[i]
\frac-\sum_^n height[i]
2n∗(n−
1)−
∑i=1
nhe
ight
[i]
把字串翻轉,從前往後插入字元,用set查詢插入字元的前乙個字元pre和後乙個字元next
a ns
[i]=
ans[
i−1]
+lcp
(pre
,str
[i])
+lcp
(str
[i],
next
)−lc
p(pr
e,ne
xt
)ans[i]=ans[i-1]+lcp(pre,str[i])+lcp(str[i],next)-lcp(pre,next)
ans[i]
=ans
[i−1
]+lc
p(pr
e,st
r[i]
)+lc
p(st
r[i]
,nex
t)−l
cp(p
re,n
ext)
ps: 需要離散化一下
#include
#include
#include
#include
#include
using
namespace std;
typedef
long
long ll;
typedef
unsigned
long
long ull;
typedef pair<
int,
int> pii;
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
const
int maxn=
1e5+10;
const
int mod=
1e9+7;
const
int inf=
0x3f3f3f3f
;const
int maxbit=20;
struct suffixarray
void
build
(int
*r,int n,
int m)
for(i=
0;i)rank[sa[i]
]=i;
for(i=
0;i1;height[rank[i++]]
=k)for
(k?k--:0
,j=sa[rank[i]-1
];r[i+k]
==r[j+k]
;k++);
}void
build_st()
//st表
intlcp
(int x,
int y)
//最長公共字首
}sa;
int hash[maxn]
,num,strcp[maxn]
,a[maxn]
;int
get_hash
(int x)
set<
int> s;
intmain()
rep(i,
0,n-
1) strcp[i]
=a[n-
1-i]
;sort
(hash+
1,hash+n+1)
; num=
unique
(hash+
1,hash+n+1)
-hash;
rep(i,
0,n-
1) strcp[i]
=get_hash
(strcp[i]);
strcp[n]=0
; sa.
build
(strcp,n,n+
100)
; sa.
build_st()
; ll sum=
0,now=1;
per(i,n-1,
0)if(l&&r) sum-
=sa.
lcp(l,r);if
(l) sum+
=sa.
lcp(l,sa.rank[i]);
if(r) sum+
=sa.
lcp(r,sa.rank[i]);
s.insert
(sa.rank[i]);
cout<(now+1)
/2-sum<<
'\n'
; now++;}
return0;
}
sam裸題
由於字符集過大,要用map維護
#include
using
namespace std;
typedef
long
long ll;
typedef
unsigned
long
long ull;
typedef pair<
int,
int> pii;
#define debug(x) cerr<<#x<<' '<#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
const
int maxn=
1e5+10;
const
int mod=
1e9+7;
const
int inf=
0x3f3f3f3f
;ll ans=0;
struct sam
, fa[maxn<<1]
, sz =
2, last =1;
void
ins(
int ch)
int q = t[p]
[ch];if
(len[p]+1
== len[q]
) fa[np]
= q;
else
ans+
=len[np]
-len[fa[np]];
}}sam;
intmain()
return0;
}
SDOI2016 生成魔咒
這是一道 sa 的練手好題 建議做之前先去做一下2408 之後你就肯定會做這道題了 首先上面那道題的答案就是 sum nn 1 sa i het i 就是對於每乙個字尾求出其能產生的子串,之後減掉和之前本質相同的子串 對於這個題,我們需要求出所有字首的本質不同的子串個數 先無腦敲上 sa 和 het...
SDOI2016 生成魔咒
魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 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...
SDOI2016 生成魔咒
魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 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...