洛谷T24438 精靈飛蠅(字尾自動機 線段樹)

2021-08-17 05:39:19 字數 1814 閱讀 6743

一上午才想出來,因為睡午覺(看《戀如雨止》)而失去了小禮物

不知什麼時候會消失的題面

題意:乙個長100的短串,乙個長50000的長串

要求支援長串某個位置修改,問長串[l,r]與短串的最長公共子串

修改不多於5000

假如沒修改

考慮什麼資訊可以得出答案 維護f

[l]=

r f[l

]=

r表示長串每個l最大的r使得[l,r]是短串的子串

顯然f單調不降

對於詢問[l

,r] [l,

r]

,二分出最小的x使得f[

x]≥r

f [x

]≥

rr−x

+1r −x

+1

可以貢獻答案 對於i

∈[l,

x−1]

i ∈[

l,x−

1]

的f[i]−i

+1f [i

]−i+

1也能貢獻答案

線段樹維護即可

考慮修改

由於短串不長,每次最多修改100個f值

與這100個值有關的長串區間也只有200那麼長

暴力再跑一次自動機

暴力修改線段樹就可以了

很厲害的題解

#include 

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define mmst(a, b) memset(a, b, sizeof(a))

#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef

long

long ll;

const

int n=200200;

int n,m,t;

int pre[n],son[n][26],dep[n],cnt=1,last=1;

int f[n];

int seg[n];

char s[n],t[n],by[5];

void insert(int x)

}}void update(int ro,int l,int r,int p,int val)

int mid=(l+r)>>1;

if(p<=mid)

update(ro*2,l,mid,p,val);

else

update(ro*2+1,mid+1,r,p,val);

seg[ro]=max(seg[ro*2],seg[ro*2+1]);

}int query(int ro,int l,int r,int zuo,int you)

void work(int l,int r,int mid)

}for(int i=l;i<=mid;i++)

f[i]=max(f[i],f[i-1]);

for(int i=l;i<=mid;i++)

update(1,1,n,i,f[i]-i+1);

}int main()

else

ans=max(ans,r-r+1);

ans=max(ans,query(1,1,n,l,r-1));

printf("%d\n",ans);}}

return

0;}

洛谷3804 模板 字尾自動機

真 玄學 還是沒有完全搞懂sam的性質啥的啊t t 我本來以為sam會很長的沒想到這麼短 這個題就是建出sam 然後建樹求出right然後 len max 直接取max即可啦 學習筆記什麼的等等吧 鴿了我也不管 附 include include include include define inf...

洛谷 P3804 字尾自動機

給定乙個只包含小寫字母的字串ss 請你求出 ss 的所有出現次數不為 11 的子串的出現次數乘上該子串長度的最大值。輸入格式 一行乙個僅包含小寫字母的字串ss 輸出格式 乙個整數,為 所求答案 輸入樣例 1 abab 輸出樣例 1 4 對於10 10 的資料,s 1000 s 1000 對於100 ...

洛谷P3804 模板 字尾自動機

題意 求字串 s 中所有出現次數不為 1 的子串的出現次數乘上該子串長度的最大值。方法 建立sam,令葉子節點 size 等於 1。按照拓撲序從下往上計數。個數大於1的就累計結果。include include include using namespace std define n 1000010...