BZOJ 字尾自動機四 重複旋律7

2022-04-30 11:12:10 字數 4200 閱讀 2152

時間限制:15000ms

單點時限:3000ms

記憶體限制:512mb

描述小hi平時的一大興趣愛好就是演奏鋼琴。我們知道一段**旋律可以被表示為一段數構成的數列。

神奇的是小hi發現了一部名字叫《十進位制進行曲大全》的作品集,顧名思義,這部作品集裡有許多作品,但是所有的作品有乙個共同特徵:只用了十個音符,所有的音符都表示成0-9的數字。

現在小hi想知道這部作品中所有不同的旋律的「和」(也就是把串看成數字,在十進位制下的求和,允許有前導0)。答案有可能很大,我們需要對(10^9 + 7)取摸。

解題方法提示

輸入第一行,乙個整數n,表示有n部作品。

接下來n行,每行包含乙個由數字0-9構成的字串s。

所有字串長度和不超過 1000000。

輸出共一行,乙個整數,表示答案 mod (10^9 + 7)。

樣例輸入

2

10109

樣例輸出

131
小hi:我們已經學習了字尾自動機,今天我們再來看這道有意思的題。

小ho:好!這道題目讓我們求的是若干的數字串所有不同子串的和。

小hi:你能不能結合字尾自動機的性質來思考如何解決本題?

小ho:這道題目既然是關於子串,那麼我知道從字尾自動機的所有狀態中包含的子串的集合恰好對應原串的所有不重複子串。

小hi:很好。那你可以先簡化問題,想想只有乙個串怎麼做?

小ho:好的。這個難不倒我。我上次已經知道如何計算乙個串所有不同子串的數量,現在這題也類似,只不過計算更加複雜一點。

小hi:那你可以詳細說說。

小ho:我們舉個例子,假設s="1122124",其實就是我們熟悉的例子"aabbabd"啦。

狀態子串

endpos

sums空串0

1112

1111

3112

1124

1122,122,22

126652

2611221,1221,221,21

12684

7112212,12212,2212,212

126848812

1291122124,122124,22124,2124,124,24,4

1248648

小ho:如果我們能像上面的**一樣求出每個狀態中包含的子串的"和",不妨記為sum(st)。那麼我們只要求出σsum(st)就是答案了。

小hi:那你講講怎麼求出每個狀態的和?

小ho:從初始狀態開始乙個個遞推出來咯。比如我們現在要求狀態6也就是的和。我們知道到達狀態6的邊(transition)有2條,分別是trans[4][1]和trans[5][1]。如果我們已經求出sum(4) = 1266, sum(5)=2,那麼我們就可以求出sum(6)=(sum(4) * 10 + 1 * |substrings(4)|]) + (sun(5) * 10 + 1 * |substring(5)|) = (12660 + 1 * 3) + (2 * 10 + 1 * 1) = 12684。

小ho:換句話說,狀態6裡的這三個子串是從狀態4的所有(3個)子串乘以10再加1得到的;狀態6裡的這個子串是從狀態5的所有(1個)子串乘以10再加1得到的。也就是說對於狀態st

sum(st) = σ。

小ho:我們知道sam的狀態和轉移構成了乙個有向無環圖,我們只要求出狀態的拓撲序,依次求出sum(st)即可。

小hi:不錯嘛。那我們回到原題的多個串的情況,怎麼解決?

小ho:多個串我就不會了 ┑( ̄д  ̄)┍

小hi:還記得我們第122周用字尾陣列求多個串的最長公共字串時用到的技巧麼?

小ho:把多個串用'#'連線起來當作乙個串來處理?

小hi:沒錯。這次我們也使用這種方法,把所有串用冒號':' (':'的acii碼是58,也就是'0'的ascii碼+10,方便處理) 連線以來。以兩個串"12"和"234"為例,"12:234"的sam如圖:

'狀態子串endpos

|valid-substrings|

sums空串1

0111

12121

12312:,2:,:00

412:2,2:2,:200

5212

612:23,2:23,:23,23,3226

712:234,2:234,:234,234,34,4

3272

小ho:看上去如果我們把每個狀態中帶冒號的子串都排除掉,好像也是可以遞推的!

小hi:沒錯。如果我們用valid-substrings(st)表示乙個狀態中所有的不帶冒號的子串,那麼對於sum(st)我們有類似的遞推式

sum(st) = σ

小ho:那麼關鍵就是|valid-substrings(st)|怎麼求出來了?

小hi:沒錯。|valid-substrings(st)|代表st中不帶冒號的子串個數,這個值恰好就是從初始狀態s到狀態st的所有"不經過冒號轉移的邊"的路徑數目。

小ho:好像有點繞。

小hi:舉個例子,對於狀態6,如果我們不經過標記為':'的轉移,那麼從s到狀態6一共有2條路徑,是s->6和s->5->6,分別對應不帶冒號的子串3和23。前面已經提到過sam的狀態和轉移構成了乙個有向無環圖,有向無環圖上的路徑數目也是乙個經典的拓撲排序問題,可以參考之前我們的討論

小ho:我明白了。建完sam之後對所有狀態拓撲排序,然後按拓撲序遞推一邊求出|valid-substrings(st)|,一邊求出sum(st)就可以了。好了,我寫程式去了。

依然是hiho怎麼說,我們怎麼做,2333~~~

1 #include 2

3#define fread_siz 1024

45 inline int get_c(void)6

1617 inline int get_i(void)18

3132 inline int get_s(int *s)

3346

47 typedef long

long

lnt;

4849

const

int maxn = 2000005;50

const

int mod = 1000000007;51

52/*

automaton

*/53

54int last = 1;55

int tail = 2;56

intfail[maxn];

57int

step[maxn];

58int next[maxn][11

];59

60 inline void build(int *s)

6186}87

else

88 fail[t] = 1

;89 last =t;90}

91}9293

/*solve pbm

*/94

95lnt ans;

96lnt sum[maxn];

97lnt sub[maxn];

98int

cnt[maxn];

99100 inline void solve(void

)101

120}

121122 head = 0, tail = 0

;123 que[tail++] = 1

;124 sub[1] = 1

;125

126while (head !=tail)

127144

}145

146 printf("

%lld\n

", ans);

147}

148149

/*main func

*/150

151int

s[maxn], len, n;

152153 signed main(void

)154

162163 s[len] = -1

;164

165build(s);

166167

solve();

168 }

@author: yousiki

hihocoder 字尾自動機四 重複旋律7

題目 在 dag 上跑乙個 dp 就好了 設 ans i 表示到了 sam 的 i 位置上所有的子串形成的數的和,之後我們順便記錄乙個方案數 d i 之後我們直接轉移就好了 ans v ans u times 10 w u,v times d u d v d u 答案是 sum ans i incl...

hihocoder 字尾自動機四 重複旋律6

題目 對於 k in 1,n 求出長度為 k 的子串出現次數最多的出現了多少次 我直到現在才理解字尾自動機上的子樹和是什麼意思 非常顯然的一點是 endpos link u endpos u 考慮到 link u 有多個兒子 於是還需要 endpos 的另外乙個性質 endpos u endpos ...

字尾陣列四 重複旋律4

我們知道乙個 旋律被表示為長度為 n 的數構成的數列。我們把一段旋律稱為 k,l 重複的,如果它滿足由乙個長度為l的字串重複了k次組成。如旋律abaabaabaaba是 4,3 重複的,因為它由aba重複4次組成。小hi想知道一部作品中k最大的 k,l 重複旋律。輸入一行乙個僅包含小寫字母的字串。字...