求乙個字串有多少本質不同的子串,這裡的不同指兩個子串的最小表示法不同.
n
<=5
e4,1
<=a
[i
]<=n
,其中n
是字串
長度,a
[i]是
字元
n<=5e4,1<=a[i]<=n,其中n是字串長度,a[i]是字元
n<=5
e4,1
<=a
[i]<=n
,其中n
是字串
長度,a
[i]是
字元首先,如果不同指字串本身不同,那麼有經典做法:先後綴排序,求出排名相鄰的字尾的lcp,然後就等於總字串個數-所有相鄰字尾的lcp的長度.
但是現在不同的定義不同,我們考慮更改hash的定義,變成"每個位置到下乙個與其相同的位置的距離"∗wi
*w^i
∗wi,其中w
ww是步長,然後就可以用線段樹維護乙個子串的hash值了,就可以二分+hash求lcp
#include
using
namespace std;
const
int maxn=
5e4+5;
typedef
unsigned
long
long ull;
const ull step=
233;
inline
intread()
while
(isdigit
(c))
return t*f;
}int n,a[maxn]
,rt[maxn]
,lst[maxn]
,p[maxn]
,ord[maxn]
;ull pw[maxn]
;ull sum[maxn<<5]
,ha;
int ls[maxn<<5]
,rs[maxn<<5]
;map<
int,ull> h[maxn]
;int cnt=0;
void
modify
(int
&now,
int l,
int r,
int x,
int val)
int mid=l+r>>1;
if(x<=mid)
modify
(ls[now]
,l,mid,x,val)
;else
modify
(rs[now]
,mid+
1,r,x,val)
; sum[now]
=sum[ls[now]
]*pw[r-mid]
+sum[rs[now]];
}void
query
(int now,
int l,
int r,
int x,
int y)
if(x<=l&&r<=y)
int mid=l+r>>1;
if(x<=mid)
query
(ls[now]
,l,mid,x,y);if
(y>mid)
query
(rs[now]
,mid+
1,r,x,y)
;return;}
bool
same
(int l,
int r,
int len)
if(h[r]
.count
(r+len-1)
)t2=h[r]
[r+len-1]
;else
return t1==t2;
}int
lcp(
int x,
int y)
bool
cmp(
int x,
int y)
intmain()
lst[a[i]
]=i;
}long
long ans=0;
for(
int i=
1;i<=n;i++
)ord[i]
=i;stable_sort
(ord+
1,ord+
1+n,cmp)
;for
(int i=
1;i<=n;i++
)ans=ans+n-i+1;
for(
int i=
2;i<=n;i++
)ans-
=lcp
(ord[i-1]
,ord[i]);
printf
("%lld\n"
,ans)
;return0;
}
一道字串練習題
給了乙個長度為n的字串,要求將其分為k段,求這k段最長的並且字典序最小的lcs.k n 1e5 小寫字母 k le n le 1e5,sum 小寫字母 k n 1e 5,小寫字 母二分 hash sa 首先可以把問題轉化為求乙個最長的並且字典序最小的字串,在原串中不重疊地出現了k次.然後二分這個字串...
一道互動練習題
的做法 考慮逐位確定 對於每個位置,往後列舉有沒有位置可以使得正確位置更多,如果有,那麼有兩種情況,1是這個位置被放到了正確的位置,2是這個位置本來應該放的數被放來了 這裡的重點是我們需要區分1和2 具體的做法是記下讓這個位置答案正確位置數變大的2個位置,將其和i一起移位 這裡是手繪示意圖.即把p1...
一道fft練習題
考場上想到的o n 2 o n 2 o n2 暴力 記f i j f i j f i j 表示前i個位置,長度為j的連擊出現的期望次數 記g i j g i j g i j 表示第到i個位置為止,目前連擊次數為j的概率 轉移時有一些細節 include using namespace std con...