P2375 [NOI2014] 动物园 题解
P2375 [NOI2014] 动物园
前言
首先是求 \(next\) 数组的知识,简单一句话概括就是 \(border\) 的 \(border\) 还是 \(border\),详见 oiwiki。
思路
那么会这个之后,题面就是求每一个位置有几个 \(border\) 的长度不超过当前位置的一般,最简单就是直接沿着 \(next\) 枚举所有符合条件(长度不大于一半) \(border\)。这样时间复杂度是 \(O(n^2)\),只能获得 \(\color{orange}50pts\)。
考虑到每一个位置的 \(border\) 是固定的,那么就提前存好 \(sum\) 表示其 \(border\) 数量,找到第一个符合条件的位置,直接加上其 \(sum\)。找位置可以用倍增存,然后直接 \(O(n\log n)\) 时间复杂度解决,成功获得 \(\color{green} 100pts\)。
#include <bits/stdc++.h>
using namespace std;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define ll long long
#define ld long double
#define re register
#define endl '\n'
#define inf 0x7f7f7f7f
#define lb(x) (x&-x)
#define pii pair<int,int>
#define fir first
#define sec second
const int N=1e6+1,mod=1e9+7,M=21;
int T,n,nxt[N],num[N],sm[N],bz[N][M],pw[N];
string s;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
cout.tie(0);
for(int i = 2;i<N;++i) pw[i]=pw[i>>1]+1;
// freop();
//↑以上为初始化↑
//------------------------------
cin >> T;
while(T--){
cin >> s,n=s.size(),s="@"+s;
for(int i = 2;i<=n;++i){
int j=nxt[i-1];
while(s[j+1]^s[i]&&j) j=nxt[j];
if(s[j+1]==s[i]) nxt[i]=++j,num[i]=1,sm[i]=sm[j]+1;
else nxt[i]=j,num[i]=0,sm[i]=sm[j];
for(int k = pw[i];~k;--k)
if(bz[j][k]>i>>1) j=bz[j][k];
if(j>i>>1) j=bz[j][0];
num[i]+=sm[j],bz[i][0]=nxt[i];
for(int k = 1;k<=pw[i];++k)
bz[i][k]=bz[bz[i][k-1]][k-1];
}
// cout << endl;
// for(int i = 1;i<=n;++i) cout << num[i] << ' ';cout << endl;
ll ans=1;
for(int i = 1;i<=n;++i) ans=ans*(num[i]+1)%mod;
cout << ans << endl;
}
return 0;
}

浙公网安备 33010602011771号