[NOI Online 2021 提高组] 积木小赛
思路不说了。
想起来自己打比赛的时候,没睡好。随便写了个\(HASH\),模数开小一半分都没有。
然后学了\(SAM\),发现这个判重不就是个水题。
\(SAM\)是字串tire的集合体。
随便\(dfs\)一下就好,然后复杂度是\(O(n^2)\)即遍历所有子串
[NOI Online 2021 提高组] 积木小赛
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 3005
#define end 0x3f3f3f3f
ll n;
char a[N],b[N];
ll nex[N][30];
ll ch[N << 1][30],link[N << 1],len[N << 1],nod = 1,las = 1;//SAM
inline void insert(ll c){
ll p = las,q = ++nod;las = q;
len[q] = len[p] + 1;
while(!ch[p][c] && p != 0){
ch[p][c] = q;
p = link[p];
}
if(p == 0)
link[q] = 1;
else{
ll x = ch[p][c];
if(len[x] == len[p] + 1){
link[q] = x;
}else{
int y = ++ nod ;//复制一个新节点
link[y] = link[x];
link[x] = link[q] = y;
len[y] = len[p] + 1;
std::memcpy(ch[y],ch[x],sizeof(ch[x]));
while(p != 0 && ch[p][c] == x){
ch[p][c] = y;
p = link[p];
}
}
}
}
ll ans;
inline void dfs(int u,int to,ll now){
if(to == end)
return;
ans ++ ;
for(int i = 0;i <= 26;++i){
if(ch[u][i])
dfs(ch[u][i],nex[to + 1][i],now * 10 + i);
}
}
int main(){
scanf("%lld",&n);
scanf("%s%s",a + 1,b + 1);
for(int i = 0;i <= 26;++i)
nex[n + 1][i] = end;
for(int i = n;i >= 1;--i){
for(int j = 0;j <= 26;++j)
nex[i][j] = nex[i + 1][j];
nex[i][a[i] - 'a'] = i;
}
for(int i = 0;i <= 26;++i)
nex[0][i] = nex[1][i];
for(int i = 1;i <= n;++i)
insert(b[i] - 'a');
dfs(1,0,0);
std::cout<<ans - 1<<std::endl;
}