1. 程式人生 > >Codeforces 1073G Yet Another LCP Problem: 字尾陣列+單調棧

Codeforces 1073G Yet Another LCP Problem: 字尾陣列+單調棧

題意:

給定一個長度為 l e n len 的串 S S , 每次詢問給定一個長度為 k

k a a 陣列和一個長度為 l l b
b
陣列,求:

i = 1 k

j = 1 l l c p ( S [ a i , l e n ] , S [ b j , l e n ] ) \sum_{i=1}^k\sum_{j=1}^llcp(S[a_i,len],S[b_j,len]) l e n 2 1 0 5 len\le2\cdot10^5

題解:

考慮一個弱化版的問題,給定兩個字串 S 1 , S 2 S_1,S_2 ,求 i = 1 l e n 1 j = 1 l e n 2 l c p ( S 1 [ i , l e n 1 ] , S 2 [ j , l e n 2 ] ) \sum_{i=1}^{len_1}\sum_{j=1}^{len_2}lcp(S_1[i,len_1],S_2[j,len_2]) .

即求兩個串的所有後綴之間的組合的 l c p lcp 之和. 容易發現,我們實際上可以把 S 1 , S 2 S_1,S_2 連線起來跑字尾陣列後,從頭到尾掃描一遍,對於屬於 S 1 S_1 的字尾,新增到單調棧裡面,同時維護和,而對於屬於 S 2 S_2 的字尾用前面維護的 S 1 S_1 的和來更新 答案即可.這樣就把從頭到尾每一個 S 2 S_2 前面的 S 1 S_1 的貢獻統計好了. 此時再反過來統計一次 S 1 S_1 前面的 S 2 S_2 的貢獻, 即可得到答案. (把 p o j 3415 poj 3415 的程式碼中的 K K 改成 1 1 ,就可以解決這個問題.原因可以自己思考一下 ).

回到這個題目,弱化版的問題與本題 的差別在於, 弱化的問題統計的時候,每一個字尾一定: 要麼屬於用來更新 S 2 S_2 S 1 S_1 ,要麼屬於用來更新 S 1 S_1 S 2 S_2 ,但是現在題目要求統計的對數變成了數組裡面的元素,因此需要判斷一下,於是乎,我們把 p o j 3415 poj 3415 的程式碼中的直接新增改成: 每一次新增進棧的元素判斷是否屬於一個數組裡面的元素,統計答案的時候判斷是否屬於另一個數組裡面的元素即可.

但是 \cdots ,我們交上去發現 T T 了,我們仔細思考題目,發現這個題目中,詢問次數非常多,但是我們每一次都用 O ( l e n ) O(len) 的方法跑了一次單調棧,複雜度很高.因此我們考慮怎麼優化:

仔細想想,我們把弱化版的問題的程式碼, 修改了新增進棧和更新答案判斷的部分. 但是沒有變換的部分是每一次新增一個字尾,更新它對前面棧的影響.但由於這個題目實際上只在下標屬於給定的陣列元素時,才會新增進棧和更新答案,因此兩個陣列元素之間的部分,都是在用 h e i g h t [ i ] height[i] 更新棧裡面的元素,而連續的一段更新實際上可以用這一段裡面的 h e i g h t height 最小值去更新,因此,我們考慮排序後直接對數組裡面的元素進行單調棧的操作,中間更新的部分直接預處理一段的 l c p lcp 來更新.

p s : ps: 此題給定的 S 1 , S 2 S_1,S_2 是相同的,所以可以直接處理. 我們將陣列元素更改一下,即可解決 S 1 , S 2 S_1,S_2 不相同的情況.

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+7;
char s[maxn];
int sa[maxn],str[maxn],_rank[maxn],height[maxn];
int t1[maxn],t2[maxn],c[maxn];
int RMQ[maxn],mm[maxn],best[20][maxn],len;
typedef pair<int,int> pr;
bool cmp(int *r,int a,int b,int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int n,int m)
{
    int i,j,p,*x=t1,*y=t2;
    //第一輪基數排序,如果s的最大值很大,可以改為快速排序
    for(i=0;i<m;i++) c[i]=0;
    for(i=0;i<n;i++) c[x[i] = str[i]]++;
    for(i=1;i<m;i++) c[i]+=c[i-1];
    for(i=n-1;i>=0;i--) sa[--c[x[i]]] = i;
    for(j=1;j<=n;j<<=1)
    {
        p=0;
        for(i=n-j;i<n;i++) y[p++]=i;
        for(i=0;i<n;i++)  if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[y[i]]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        //根據sa和x陣列計算新的x陣列
        swap(x,y);
        p=1; x[sa[0]]=0;
        
            
           

相關推薦

Codeforces 1073G Yet Another LCP Problem $SA$+單調

題意 給出一個字串\(s\)和\(q\)個詢問。 每次詢問給出兩個長度分別為\(k,l\)的序列\(a\)和序列\(b\)。 求\(\sum_{i=1}^{k}\sum_{j=1}^{l}lcp(s[a_i…n],s[b_j…n])\) Solution \(SA\)練習題。 求出\(height\)陣

Codeforces 903G Yet Another Maxflow Problem - 線段樹

vector 維護 update win32 main spa 一個 tps print 題目傳送門   傳送門I   傳送門II   傳送門III 題目大意   給定一個網絡。網絡分為$A$,$B$兩個部分,每邊各有$n$個點。對於$A_{i} \ (1

CodeForces - 868F Yet Another Minimization Problem

|| inf -- efi min bits get 移動 個數 Description 給定一個長度為 \(n(n\le 10^5)\) 的數列,第 \(i\) 個數是 \(a_i\in[1,n]\) ,要求將其劃分為 \(k(2\le k\le min(20,n))\)

codeforces CF903G Yet Another Maxflow Problem 線段樹

img several http 答案 codeforce mes take 感謝 city $ \Rightarrow $ 戳我進CF原題 G. Yet Another Maxflow Problem time limit per test: 4 seconds mem

Codeforces 868F. Yet Another Minimization Problem【決策單調性優化DP】【分治】【莫隊】

LINK 題目大意 給你一個序列分成k段 每一段的代價是滿足\((a_i=a_j)\)的無序數對\((i,j)\)的個數 求最小的代價 思路 首先有一個暴力dp的思路是\(dp_{i,k}=min(dp_{j,k}+calc(j+1,i))\) 然後看看怎麼優化 證明一下這個DP的決策

CodeForces 868F Yet Another Minimization Problem(決策單調性優化 + 分治)

efi isp size fine logs res namespace c++ 得到 題意 給定一個序列 \(\{a_1, a_2, \cdots, a_n\}\),要把它分成恰好 \(k\) 個連續子序列。 每個連續子序列的費用是其中相同元素的對數,求所有劃分中的費用之

字尾陣列+單調--luogu[HAOI2016]找相同字元

傳送門 可以把兩個字串通過一個特殊字元連起來然後字尾陣列求出 h h h 想到一個

2018.11.24 poj3415Common Substrings(字尾陣列+單調

傳送門 常數實在壓不下來(蒟蒻開O(3)都過不了)。 但有正確性233. 首先肯定得把兩個字串接在一起。 相當於 h e

bzoj 4453 cys就是要拿英魂!——字尾陣列+單調+set

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4453 詢問離線,按R排序。 發現直接用 rk[ ] 的錯誤情況就是前面的某個位置 j 和自己位置 i 的 LCP 長度大於 i 到當前 R 的長度,這時雖然 rk[ j ] < rk[ i ]

BZOJ 3238 [Ahoi2013]差異 (字尾陣列+單調)

題目大意:求$\sum_{1\leq i<j \leq N} suf_{i}+suf_{j}-2\cdot lcp(suf_{i},suf_{j})$ 先是字尾陣列打錯了,又是把+=打成了=,我是zz 轉化式子,原式=$\sum_{i=1}^{n-1}(i+1)\cdot i-\sum_{1\leq

BZOJ.4453.cys就是要拿英魂!(字尾陣列 單調 二分)

BZOJ 求字典序最大,容易想到對原串建字尾陣列求\(rk\)。 假設當前區間是\([l,r]\),對於在\([l,r]\)中的兩個字尾\(i,j\)(\(i<j\)),顯然我們不能直接比較\(rk_i,rk_j\)來比較\(i,j\)在\([l,r]\)中誰的字典序更大。(比如對於串\(babb\

BZOJ 4453 cys就是要拿英魂!(字尾陣列+單調+平衡樹)

一開始的時候感覺就是一個主席書裸題。 然後發現自己錯了。 首先建出字尾陣列。 設\(i<j\) 如果\(rk[i]>rk[j]\)顯然i更優。 如果\(rk[i]<rk[j]\)不一定是j更優。 當\(i+lcp(i,j)-1<=j\)時是\(j\)優,否則\(i\)更優。 所以我們有

CodeForces 863D Yet Another Array Queries Problem 暴力

names scanf amp pan turn 得到 include net == CodeForces 863D 題意:長度為 n 的數組 a[] ,有兩個操作: 1、區間 [l,r] 的數向右移,即 a[i+1] 變為 a[i],a[l] 變為 a[r] 。 2、

CodeForces - 1000D Yet Another Problem On a Subsequence

CP get highlight #define oid brush for turn force 題面在這裏! 好智障的一個dp啊,一段開頭的數字相當於下面要跟多少個數,直接滾動數組dp就行了。。。 #include<bits/stdc++.h&g

【CF903G】Yet Another Maxflow Problem 線段樹

pri soft string ace 題解 pda 容量 tro tor 【CF903G】Yet Another Maxflow Problem 題意:一張圖分為兩部分,左邊有n個點A,右邊有m個點B,所有Ai->Ai+1有邊,所有Bi->Bi+1有邊,某些

CodeForces - 393E Yet Another Number Sequence

space 二項式定理 ever title #define lse size void hat Discription Everyone knows what the Fibonacci sequence is. This sequence can be defined

[CF903G]Yet Another Maxflow Problem

發的 void b+ std sdi 需要 -a lin clu [CF903G]Yet Another Maxflow Problem 題目大意: 有\(A\)類點和\(B\)類點各\(n(n\le2\times10^5)\)個,所有\(A_i\)到\(A_{i+1}\)

CF868 F. Yet Another Minimization Problem 決策單調優化 分治

efi getch 預處理 algo 單調性 代碼 arr 最優決策 ref 題目鏈接 CF868F. Yet Another Minimization Problem 題解 \(f_{i,j}=\min\limits_{k=1}^{i}\{f_{k,j-1}+w_{k,i

Hackerrank:Yet Another KMP Problem

This challenge uses the famous KMP algorithm. It isn't really important t