魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 \(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,1,1]\) 三種,最初 s 為空串。
共進行 \(n\) 次操作,每次操作是在 \(s\) 的結尾加入乙個魔咒字元。每次操作後都需要求出,當前的魔咒串 \(s\) 共有多少種生成魔咒。
考慮在加入第 \(i\) 個數字之後會有多少種新的子串生成。顯然數量等於 \(i\) 減有多少個子串之前出現過。
那麼我們只需要找到乙個 \(j(j使得 \(i\) 與 \(j\) 的 lcs 盡量長即可。假設 lcs 長度為 \(l\),顯然貢獻為 \(i-l\)。
那麼就把字串反過來跑一遍 sa,然後從後往前列舉數字,用乙個 set 維護之前列舉過的所有數字的 \(rank\),在 set 上 lower_bound 即可找到兩個與 \(rank[i]\) 最近的位置,用較大的 lcp 去更新即可。
時間複雜度 \(o(n\log n)\)。
#include #define ak =
#define ioi 233
using namespace std;
typedef long long ll;
const int n=100010,lg=18,inf=1e9;
int n,m,s[n],sa[n],x[n],y[n],c[n],rk[n],height[n],lg[n],rmq[n][lg+1];
ll ans,quantask;
mapb;
setvis;
void sa()
}void geth()
}void getst()
sa(); geth(); getst();
vis.insert(-inf); vis.insert(inf);
lg[1]=0;
for (int i=2;i<=n;i++)
lg[i]=lg[i>>1]+1;
for (int i=n;i>=1;i--)
if (quantask ak ioi) return 0;
else return -1;
}
P4070 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...
P4070 SDOI2016 生成魔咒(SAM)
題意 一開始有乙個空陣列,n次操作,每次操作都是在陣列的末尾追加乙個數x,要求操作之後輸出陣列中本質不同的子陣列數量。資料範圍 n 1e5,1 x 1e9 解法 本質不同子串容易想到sam,本質不同的子串數量 sum l i l fa i 每次插入乙個新數的時候,設新節點為np,那麼答案累加l np...
P4070 SDOI2016 生成魔咒 解題報告
link 一開始給乙個空串 s ss,每次在其最後加入乙個字元 x xx,詢問每次加入後 s ss 的本質不同的非空子串的個數。s 105 1 x 109 s le 10 5,1 le x le 10 9.s 10 5,1 x 10 9.具體地說,加入乙個字元 x xx 得到的貢獻就為 len np...