一上午才想出來,因為睡午覺(看《戀如雨止》)而失去了小禮物
不知什麼時候會消失的題面
題意:乙個長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...