點此看題
字尾自動機亂殺。
他問的是字首之間的最長字尾,我們對正串建出字尾自動機,然後把字首在自動機上面打上標記。根據字尾自動機的性質,最長字尾就是兩個字首在 \(\tt parent \;tree\) 上 \(\tt lca\) 的 \(len\)
對於乙個字首對 \((l,r)\) ,那麼他可以對 \(l\leq l,r\leq r\) 的詢問 \((l,r)\) 產生貢獻。因為是 \(\tt lca\) ,所以可以想到通過樹上啟發式合併找出這些字首對,那麼我們在合併子樹的時候就要考慮子樹之間新產生的點對。
貌似這樣字首對的數量是 \(o(n^2)\) 的,合併的時候我們只需要找最接近的字首,因為貢獻都是一樣的,但是找最接近的能貢獻到的是最多的,所以數量是 \(o(n\log n)\),用 \(\tt set\) 維護啟發式合併。
那麼時間複雜度 \(o(n\log^2 n)\),最後算貢獻的時候本質上是乙個二維偏序,所以直接排序就行了。
#include #include #include #include using namespace std;
const int m = 200005;
int read()
while(c>='0' && c<='9')
return x*f;
}int n,m,k,tot,cnt,last,bit[m],f[m],ans[m];char t[m];
sets[m];
struct edge
}e[2*m];
struct node
a[m];
struct zxy
; if(nxt!=s[u].end()) p[++k]=zxy;
s[u].erase(*it);
} for(it=s[v].begin();it!=s[v].end();it++)
s[u].insert(*it); }}
int lowbit(int x)
void add(int x,int y)
int ask(int x)
signed main()
for(int i=2;i<=cnt;i++)
dfs(1,0);
sort(p+1,p+1+k);
for(int i=1;i<=m;i++)
; }sort(q+1,q+1+m);
for(int i=1,j=1;i<=m;i++)
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
雅禮集訓2017Day7事情的相似度
bitset幫助離線合併實現o n w 然後暴力就可以在n 100000時為所欲為 其實還是有點思想,從大到小列舉height值,這樣每次涉及到的問題的答案一定是height 另外脫機會mle?那就分兩次離唄。沒有什麼是一次離線解決不了的,如果有,那就兩次。從height大到小更新可以簡化轉移,因為...
雅禮集訓 2017 Day7 事情的相似度
text 處理了一下排版問題,以及新增 rm lct 做法。如果沒有原題測試,還不知道這道題還要被咕多久.本來就已經咕了乙個寒假了.傳送門 to loj 最長公共字尾,很難不讓人想到 tt sam 的 text 因為在 text 上有 兩個串的最長公共字尾,即為他們所代表的點在樹上的 lca 對應的...
雅禮集訓 2017 價
傳送門 乙個不太顯然的最小割做法。我們這麼連邊 源點向藥物連 infty p i 容量的邊,藥物向它對應的藥材連 infty 容量的邊,藥材向匯點連 infty 容量的邊。用源點的流量減去最小割,再負回來就可以求出答案了。怎麼理解呢?割掉一條邊表示不選其對應的藥物或藥材,我們發現最後的方案一定是完美...