• 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;
    }
    
  • 相关阅读:
    367 Valid Perfect Square 有效的完全平方数
    365 Water and Jug Problem 水壶问题
    363 Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K
    357 Count Numbers with Unique Digits 计算各个位数不同的数字个数
    SpringBoot (四) :thymeleaf 使用详解
    SpringBoot(三) :Spring boot 中 Redis 的使用
    SpringBoot(二) :web综合开发
    SpringBoot (一) :入门篇
    程序员最核心的竞争力是什么?
    Java面试题:多继承
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14002030.html
Copyright © 2020-2023  润新知