zoukankan      html  css  js  c++  java
  • 【题解】NOI2014动物园

    传送门:洛谷P2375

    一直到写到这道题目才发现我一直都理解了假的KMP……fail数组:fail[i]为从1-i(包含i)在内的字符串,相同的最长前后缀长度。

    那么我们可以先思考暴力:先求出所有的fail,再不断往上跳,那么跳到的节点中(fail<<1)<i的个数即为num值。但这样的复杂度太高了,所以我们要进一步优化。

    可以发现每一个节点所指向的fail节点是唯一的,但一个点可能是多个节点的fail,这是一个树形的关系。且在这个树形关系上,越靠近根节点的fail值也就越小。所以我们逐层标记Num值,直到找到符合条件的节点,则这个节点所标记的值就是它&它上方所有节点的个数。(若该点满足条件,则在它之上的一定满足)。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 10000
    #define ll long long
    #define p 1000000007
    int fail[maxn], num[maxn];
    char s[maxn];
    ll solve()
    {
        ll ans = 1;
        int len = strlen(s + 1);
        memset(fail, 0, sizeof(fail));
        memset(num, 0, sizeof(num));
        num[1] = 1;
        for(int i = 2, j = 0; i <= len; i ++)
        {
            while(j && s[i] != s[j + 1]) j = fail[j];
            if(s[i] == s[j + 1]) j ++;
            fail[i] = j;
            num[i] = num[j] + 1; 
        }
        for(int i = 2, j = 0; i <= len; i ++)
        {
            while(j && s[i] != s[j + 1]) j = fail[j];
            if(s[i] == s[j + 1]) j ++;
            while((j << 1) > i) j = fail[j];
            ans = (num[j] + 1) * ans;
            ans %= p;
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T --)
        {
            scanf("%s", s + 1); 
            printf("%lld
    ", solve());
        }
        return 0;
    }
  • 相关阅读:
    bootstrap
    史上最全Html和CSS布局技巧
    三种实现左右固定,中间自适应的三栏布局方式
    网页布局常用样式属性
    去除inline-block间隙的几种方法
    HTML&CSS——使用DIV和CSS完成网站首页重构
    I want to be a Great Web Front-end Developer
    js常用函数汇总(不定期更新)
    关于git stash的应用总结
    vue 自定义指令
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8427443.html
Copyright © 2011-2022 走看看