zoukankan      html  css  js  c++  java
  • 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 suffix s[i....n-1].

    (the prefix means s[0...i] )

    解法:假设知道了num[i]表示i開始的后缀s[i....n]跟前缀s[1...]之间的公共的前缀,那么以i开头的后缀中就匹配了num[i]个前缀了

    所以i这个后缀出现的前缀的数量实际上就是num[i] + num[i+1] + .. num[n]. 求出来之后高速幂求斐波那契数列对应项大小就可以。求lcp的时候是二分+hash;字符串hash中,seed为31(java库源代码中是这个数,应该是效果比較好的) 

    代码:

    /******************************************************
    * author:xiefubao
    *******************************************************/
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <set>
    #include <stack>
    #include <string.h>
    //freopen ("in.txt" , "r" , stdin);
    using namespace std;
    
    #define eps 1e-8
    #define zero(_) (abs(_)<=eps)
    const double pi=acos(-1.0);
    typedef long long LL;
    const int Max=100010;
    const int INF=1000000007;
    const int hashseed=31;
    
    LL seed[Max];
    LL has[Max];
    char s[Max];
    LL num[Max];
    int len=0;
    struct matrix
    {
        LL num[2][2];
        matrix()
        {
            memset(num,0,sizeof num);
        }
    };
    matrix operator*(const matrix& a,const matrix& b)
    {
        matrix ans;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
            ans.num[j][k]+=(a.num[j][i]*b.num[i][k])%INF;
        return ans;
    }
    matrix operator^(matrix a,LL n)
    {
        matrix ans;
        ans.num[0][0]=1;
        ans.num[1][1]=1;
        while(n)
        {
            if(n&1)
            {
                ans=ans*a;
            }
            a=a*a;
            n>>=1;
        }
        return ans;
    }
    LL getans(LL t)
    {
        if(t==0)
            return 0;
        if(t<=2)
            return 1;
        matrix tool;
        tool.num[0][0]=1;
        tool.num[0][1]=1;
        tool.num[1][0]=1;
        tool=tool^(t-1);
        return tool.num[0][0]%INF;
    }
    void init()
    {
        seed[0]=1;
        for(int i=1; i<Max; i++)
            seed[i]=(seed[i-1]*hashseed)%INF;
    }
    LL Hash(int i,int L)
    {
        return ((has[i]-has[i+L]*seed[L])%INF+INF)%INF;
    }
    bool OK(int i,int l)
    {
        return Hash(0,l)==Hash(i,l);
    }
    void getnum(int i)
    {
        int left=i,right=len-1;
        while(left<=right)
        {
            int middle=(left+right)/2;
            if(OK(i,middle-i+1))
                left=middle+1;
            else
                right=middle-1;
        }
        num[i]=right-i+1;
    }
    void makehash()
    {
        for(int i=len-1;i>=0;i--)
        {
            has[i]=(has[i+1]*hashseed+s[i])%INF;
        }
        num[0]=len;
        for(int i=1;i<len;i++)
        {
            getnum(i);
        }
    }
    int main()
    {
        init();
       while(scanf("%s",s)==1)
       {
           memset(has,0,sizeof has);
           len=strlen(s);
           makehash();
           for(int i=len-1;i>=0;i--)
            num[i]+=num[i+1];
           LL ans=0;
           for(int i=0;i<len;i++)
            ans=(ans+getans(num[i]))%INF;
           cout<<ans<<'
    ';
       }
        return 0;
    }
    


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    ANDROID STUDIO系列教程一--下载与安装
    Linux发邮件之mail命令
    Linux/CentOS关闭图形界面(X-window)和启用图形界面命令
    SVN四部曲之SVN设置详解深入
    构造函数 (C++)
    C++的构造函数和析构函数
    当你输入一个网址的时候,实际会发生什么?
    C++ 风格与技术 FAQ(中文版)
    二分查找算法(递归与非递归两种方式)
    c++模板
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4876378.html
Copyright © 2011-2022 走看看