生成魔咒 SDOI

2021-10-02 09:37:29 字數 3670 閱讀 2907

題目鏈結

對於原串的每個字首,求有多少個不同的子串.

對於長度為n

nn 的串,子串個數為 n∗(

n−1)

2−∑i

=1nh

eigh

t[i]

\frac-\sum_^n height[i]

2n∗(n−

1)​−

∑i=1

n​he

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...