神題啊...
首先我們考慮68分的暴力:
對於詢問串的每個位置$i$,我們維護乙個$lim_$表示以$i$為終點向前至多能與模式串匹配多長,這一點可以在把詢問串放在模式串的字尾自動機上跳躍得到
接下來考慮統計答案:
對於詢問串同樣建起乙個字尾自動機,我們知道字尾自動機上的每個節點維護的位置是一些長度連續的子串,同時對應有乙個相同的$endpos$集合,因此我們記錄下每個節點$endpos$集合中的第乙個位置$tag$,那麼這個節點$p$對答案的貢獻即為$max(0,len-max(len_},lim_}))$
為什麼?
我們考慮這個節點維護的子串數量即為$len_-len_}$,而同時最多向前匹配的長度是$lim_}$,因此這個點合法的子串數量是$len_-lim_}$,那麼兩個取最小值就是這個點的貢獻,也即減去$max(len_},lim_})$
這樣的話,我們只需在模式串的字尾自動機上跑一次詢問串,然後遍歷一次詢問串的字尾自動機即可
接下來考慮正解:
仍然建起兩個字尾自動機,唯一的區別只是在匹配的時候被匹配到的點必須在詢問給出的區間之中
那麼我們對於模式串就要維護每個節點的整個$endpos$集合,這樣我們在匹配時就要確保跳到的點$endpos$集合中至少有乙個在詢問區間之中
因此我們對模式串上的字尾自動機每個節點開一棵權值線段樹,用線段樹合併維護每個節點的$endpos$集合即可
查詢時查詢區間$[l+當前匹配長度,r]$
注意這時由於我們可以令當前匹配長度連續變化,因此如果失配只是匹配長度減一繼續匹配
如果匹配長度減到了當前節點的$pre$的len,再跳$pre$指標
#include #include#include
#include
#include
#include
#include
#include
#include
#define ll long long
using
namespace
std;
char s[500005],t[500005
];int
lens,lent,siz;
int lim[500005
];vector
v[1000005
];int ls[40000005],rs[40000005],rot[1000005
];int
tt;void update(int &rt,int l,int r,int
pos)
int merge(int x,int
y)bool query(int rt,int l,int r,int lq,int
rq)struct
sam
void ins(int
c)
int nwq=++tot;
tag[nwq]=tag[lsq];
len[nwq]=len[lsp]+1
; pre[nwq]=pre[lsq],pre[lsq]=pre[nwp]=nwq;
memcpy(tranc[nwq],tranc[lsq],
sizeof
(tranc[lsq]));
while(lsp&&tranc[lsp][c]==lsq)tranc[lsp][c]=nwq,lsp=pre[lsp];
}las=nwp;
}void
buildtree()
void dfs(int
x)
}void match(char *p,int lq,int
rq)
if(!mlen)break
; mlen--;
if(mlen==len[pre[now]])now=pre[now];
}lim[i]=mlen;}}
}s,t;
intmain()
return0;
}
BZOJ 5416 Noi2018 氣泡排序
bzoj 5416 noi2018 氣泡排序 dp 組合數 樹狀陣列 好題。合法的排列的交換次數剛好是交換次數的下界,也就是說不能有多餘的交換。也就是對於ai這個數,只能從i到ai這乙個方向走。考慮x,y,z三個數 x y z y需要和x z各交換一次,這顯然不能使y這個數滿足只向乙個方向移動這個條...
刷題 BZOJ 5415 Noi2018 歸程
考試的時候打的可持久化並查集,沒調出來qaq 後面知道了kruskal重構樹這個東西,感覺好簡單啊 這道題就建出kruskal重構樹後,對於兩個點找到它們的lca,其子樹min就是答案 include define ui unsigned int define ll long long define...
NOI2018 氣泡排序
noi2018 氣泡排序 題解性質 模型轉化 首先,乙個排列是 好 的,當且僅當 每個數,要麼是字首最大值,要麼是字尾最小值。討論i和pi的關係即可證明 也就是,排列不能存在 3的下降子串行!換句話說,假設之前填了i個數,最大值是mx,那麼第i 1個數,要麼是剩下數的最小值,要麼是比mx大的數。字典...