acdream 1116 Gao the string!

分析:实际上,我们用next[i]表示 T[i-n] 和T[1-n]的最长公共前缀,那么a[i]=next[i] +next[i+1]...... +next[n];  最长公共前缀(lcp)有3种方法 : 扩展kmp  ,hash 和后缀数组 。

方法一  :扩展kmp

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mmax= 100010;
const int mod=1000000007;
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
typedef long long LL;
//typedef unsigned long long ULL;
struct mar
{
    LL a[2][2];
    mar()
    {
        a[0][0]=a[0][1]=a[1][0]=1;
        a[1][1]=0;
    }
    mar operator * (const mar &A)
    {
        mar B;
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                B.a[i][j]=0;
                for(int k=0;k<2;k++)
                    B.a[i][j]+=a[i][k]*A.a[k][j];
                 B.a[i][j]%=mod;
            }
        }
        return B;
    }
    void pri()
    {
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                printf("%lld%c",a[i][j],j==1?'\n':' ');
    }
};

mar unit()
{
    mar aa;
    aa.a[0][0]=aa.a[1][1]=1;
    aa.a[0][1]=aa.a[1][0]=0;
    return aa;
}
mar powmod(mar A,LL n)
{
    mar res=unit();
    mar tmp=A;
    for(;n;n/=2)
    {
        if(n&1)
            res=res*tmp;
        tmp=tmp*tmp;
    }
    return res;
}
LL getFib(LL n)
{
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    mar B;
    mar AA=powmod(B,n-1);
    return AA.a[0][0];
}

int next[mmax];

void get_next(char *s)
{
    int n=strlen(s);
    int i,j,k;
    for(j=0;1+j<n && s[j]==s[1+j];j++);
    next[1]=j;
    k=1;
    for(i=2;i<n;i++)
    {
        int len=k+next[k],L=next[i-k];
        if(L<len-i)
            next[i]=L;
        else
        {
            for(j=max(0,len-i);i+j<n && s[j]==s[i+j];j++);
            next[i]=j;
            k=i;
        }
    }
    next[0]=n;
}

char str[mmax];
int main()
{
    while(scanf("%s",str)!=EOF)
    {
        int n=strlen(str);
        memset(next,0,sizeof next);
        get_next(str);
        LL sum=0;
        for(int i=n-1;i>=0;i--)
        {
            next[i]+=next[i+1];
            sum+=getFib(next[i]);
            sum%=mod;
        }
        cout<<sum<<endl;
    }
}

方法2: hash

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mmax= 100010;
const int mod=1000000007;
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
typedef long long LL;
typedef unsigned long long ULL;
struct mar
{
    LL a[2][2];
    mar()
    {
        a[0][0]=a[0][1]=a[1][0]=1;
        a[1][1]=0;
    }
    mar operator + (const mar &A)
    {
        mar B;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            {
                B.a[i][j]=a[i][j]+A.a[i][j];
                B.a[i][j]%=mod;
            }
        return B;
    }
    mar operator * (const mar &A)
    {
        mar B;
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                B.a[i][j]=0;
                for(int k=0;k<2;k++)
                {
                    B.a[i][j]+=a[i][k]*A.a[k][j];
                    B.a[i][j]%=mod;
                }
            }
        }
        return B;
    }
    void pri()
    {
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                printf("%lld%c",a[i][j],j==1?'\n':' ');
    }
};

mar unit()
{
    mar aa;
    aa.a[0][0]=aa.a[1][1]=1;
    aa.a[0][1]=aa.a[1][0]=0;
    return aa;
}
mar powmod(mar A,LL n)
{
    mar res=unit();
    mar tmp=A;
    for(;n;n/=2)
    {
        if(n&1)
            res=res*tmp;
        tmp=tmp*tmp;
    }
    return res;
}
LL getFib(LL n)
{
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    mar B;
    mar AA=powmod(B,n-1);
    return AA.a[0][0]%mod;
}

char str[mmax];
ULL  Ha[mmax];
ULL  Pow[mmax];
void get_hash(char *s)
{
    Ha[0]=0;
    Pow[0]=1;
    for(int i=0;s[i];i++)
    {
        Pow[i+1]=Pow[i]*131;
        Ha[i+1]=Ha[i]+Pow[i]*s[i];
    }
}
LL cnt[mmax];
int main()
{
    while(scanf("%s",str)!=EOF)
    {
        int n=strlen(str);
        get_hash(str);
        for(int i=1;i<=n;i++)
        {
            int l=i,r=n+1;
            while(l<r)
            {
                int mid=(l+l)>>1;
                if(Ha[mid]-Ha[i-1]==Ha[mid-i+1]*Pow[i-1])
                    l=mid+1;
                else
                    r=mid;
            }
            cnt[i]=r-i;
        }
        for(int i=n-1;i>=1;i--)
            cnt[i]+=cnt[i+1];
        LL sum=0;
        for(int i=1;i<=n;i++)
        {
            sum+=getFib(cnt[i]);
            sum%=mod;
        }
        cout<<sum<<endl;
    }
    return 0;
}

方法3:后缀数组 (TLE 中。。。 )   刚学后缀数组  没能过

时间: 2024-10-26 10:46:40

acdream 1116 Gao the string!的相关文章

Acdreamoj1116(Gao the string!)字符串hash+二分+矩阵快速幂

Problem Description give you a string, please output the result of the following function mod 1000000007 n is the length of the string f() is the function of fibonacci, f(0) = 0, f(1) = 1... a[i] is the total number of times any prefix appear in the

acdream1116 Gao the string!(hash二分 or 后缀数组)

问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数.我一开始做的时候想了好久,后来看了别人的解法才恍然大悟.对于一个后缀来说 s[i...n-1]来说,所有与它匹配的前缀必然是和 s[i+1...n-1]  s[i+2...n-1] ....s[n-1..n-1]里的前缀匹配的,因而如果我们定义一个num[i]表示的是后缀s[i...n-1]与前缀的总长公共前缀,那么num[i]+num[i+1]+..num[n-1]就是前缀在后缀i里出现的次数

acdream1116 Gao the string!(扩展KMP)

今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是L的话,则: s[i-L+1...i]=t[0...L] 而所谓的失配指针f[i]指的就是当前i点失配时要匹配的长度,实际是用t文本串去匹配t. 扩展KMP则是以s[i]为起始的串和 t前缀匹配的最长的长度. 假如这个长度的话,则: s[i..i+L-1]=t[0...L] 扩展KMP里的nxt数组

Zoj 3535 Gao the String II (AC自己主动机+dp)

题目大意: 用集合A中的串构造出一个串,使之让很多其它的setB中的串成为他的子串. 思路分析: 和 Codeforces 86C 几乎相同. 只是这里是要用A中的构造. 先用A 和 B的串构造一个自己主动机.然后对于A集合的尾结点给出一个最大后缀匹配,对于B集合的尾结点给一个权值. dp[i][j][k] 表示已经构造出来了一个长度为i的串,如今走到了自己主动机的j结点.i长度后面有k个字符是没有匹配到的. 继续在自己主动机上走进行状态转移. if(isword >= k +1 )dp [i+

Zoj 3535 Gao the String II (AC自动机+dp)

题目大意: 用集合A中的串构造出一个串,使之让更多的setB中的串成为他的子串. 思路分析: 和 Codeforces 86C 差不多. 不过这里是要用A中的构造. 先用A 和 B的串构造一个自动机.然后对于A集合的尾结点给出一个最大后缀匹配,对于B集合的尾结点给一个权值. dp[i][j][k] 表示已经构造出来了一个长度为i的串,现在走到了自动机的j结点,i长度后面有k个字符是没有匹配到的. 继续在自动机上走进行状态转移. if(isword >= k +1 )dp [i+1] [j->n

[HDOJ5098]Smart Software Installer(字符串处理,记忆化搜索)

题目链接:https://vjudge.net/problem/HDU-5098 题意:给软件安装清单,有些软件需要一些软件安装之前安装.每个软件安装前可能需要重启也可能不需要,问最少需要重启几次. 处理完字符串以后DFS,找一条需要重启的软件安装链中最长的. gao()大法好. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 2020; 5 char tmp[maxn]; 6 map<stri

0728二维数组/集合

二维数组int [,] array = new int[5,3];//有五个一维数组,每一个一维数组有3个元素 /打印出来一个“王”这个字string[,] wang = new string[,]{  {" ","■","■","■","■","■"," "}, {" "," "," ","■&q

AC自动机- 自我总结

AC自动机算法总结  No.1 What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一. 简单的说,KMP用来匹配一个模式串:但如果现在有多个模式串需要在同一篇文章中出现,现在就需要Aho-Corasick automaton算法了. 不要天真的以为AC自动机为auto-Accept,虽然他能让你AC一些题. No.2 My Understanding About Aho-Corasick automato

7.28

int[] shu = new int[] { 1,2,3}; //二维数组 int [,] array = new int[4,2]; //4,表示有四个一维数组 //2,表示每一个一维数组有2个元素 int[,] shuzu = new int[,] { {1,2}, {3,4}, {5,6}, {7,8} }; for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { Console.Write(shuzu[i,j]+&quo