NOI2014 动物园题解

2种解法, SB O(nlogn) 和 SB O(n) 。听到过另一种牛逼 O(n), 感觉有点假就没写。

SB O(n log n), 首先都知道 nxt 的指向关系可以构成一颗内向树, 随便二分一下就行了。

//sb O(n log n)
#include<bits/stdc++.h>

using namespace std;

const int N = 1000003, mo = 1e9+7;

int n;
char s[N];

int ecnt, hd[N];
struct edge{int v,nt; } e[N];
void ad(int x,int y) {
    e[++ecnt] = (edge){y, hd[x]};
    hd[x] = ecnt;
}

int nxt[N];
long long ans;
int sta[N];

void dfs(int x,int fa,int d) {
    if(x>=2) {
        int l=0, r=*sta;
        while(l!=r)
        {
            int mid = (l+r+1) >> 1;
            if(sta[mid]<=x/2) l=mid;
            else r=mid-1;
        }
        ans = ans*(l+1ll) % mo;
    }
    if(x) sta[++*sta] = x;
    for(int i=hd[x],y=e[i].v; i; i=e[i].nt,y=e[i].v)
        if(y!=fa) dfs(y,x,d+1);
    --*sta;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s",s+1);
        n = strlen(s+1);
        for(int i=2,j=0; i<=n; ++i) {
            while(j && s[i]!=s[j+1]) j=nxt[j];
            if(s[i] == s[j+1]) ++j;
            nxt[i]=j;
        }
        // input
        ecnt = 0;
        for(int i=0;i<=n;++i) hd[i]=0;
        for(int i=1;i<=n;++i) ad(nxt[i],i);
        
        *sta = 0;
        ans = 1ll;
        dfs(0,0,0);
        cout << ans << '
';
    }
    return 0;
}

虽然比较 sb , 但这个做法这个是 O(n) 的, 思路来源于暴跳 nxt, 发现 i-1 的超过 (lfloordfrac{i-1}{2} floor) 的 Border 不可能通过加一个字符成为 i 的不超过 (lfloordfrac{i-1}{2} floor) 的 Border, 所以再开个 nxt2 数组记录最长的不超过 (lfloordfrac{i-1}{2} floor) 的 Border, 随便搞搞就行了, 复杂度和经典 kmp 的复杂度一样分析, 是均摊 O(n) 的。

// sb O(n)
#include<bits/stdc++.h>
using namespace std;
#define li long long
const int maxn = 1e6+5;
const int mod = 1000000007;

int len, nxx[maxn], nxt[maxn];
char s[maxn];

int dep[maxn];
int main()
{
	int n; cin>>n; while(n--) {
		scanf("%s", s+1); len=strlen(s+1);
		for(int i=2,j=0,k=0;i<=len;++i) {
			while(j&&s[j+1]!=s[i]) j=nxt[j];
			if(s[j+1]==s[i]) ++j;
			nxt[i]=j;
			while(k+1>i/2) k=nxt[k];
			while(k&&s[k+1]!=s[i]) k=nxt[k];
			if(s[k+1]==s[i]) ++k;
			nxx[i] = k;
		}
		dep[0] = 1;
		for(int i=1;i<=len;++i) dep[i]=dep[nxt[i]]+1;
		li ans = 1ll;
		for(int i=1;i<=len;++i) ans = 1ll*ans*dep[nxx[i]]%mod;
		cout<<ans<<'
';
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tztqwq/p/14002030.html