ACdream 1116 Gao the string! (扩展KMP+矩阵快速幂)

题目链接:
ACdream 1116

题意:
give you a string, please output the result of the following function mod 1000000007
i=n1i=0f(a[i])
n is the length of the string。
f(i) 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....n1] .
(the prefix means s[0...i] )
比如 :输入: aa ,输出: 3
1.对于aa 这个后缀,前缀 a 出现了两次,前缀 aa 出现了一次,总共三次。
2.对于 a 这个后缀,前缀 a 出现了一次。
所以答案是 f(3)+f(1)=1+2=3

题解:
我们用 next[i]+1 表示 T[in] T[1n] 的最长公共前缀,那么 a[i]=next[i]+next[i+1]......+next[n]
求最长公共前缀 (lcp) 3 种方法 : 扩展kmp , hash 和后缀数组 。

AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
//using namespace std;
const int mod = 1e9+7;
struct matrix
{
    long long factor[2][2];
}M;
matrix multi(matrix x,matrix y)
{
    matrix temp;
    temp.factor[0][0] = (x.factor[0][0] * y.factor[0][0] + x.factor[0][1] * y.factor[1][0]) % 1000000007;
    temp.factor[0][1] = (x.factor[0][0] * y.factor[0][1] + x.factor[0][1] * y.factor[1][1]) % 1000000007;
    temp.factor[1][0] = (x.factor[1][0] * y.factor[0][0] + x.factor[1][1] * y.factor[1][0]) % 1000000007;
    temp.factor[1][1] = (x.factor[1][0] * y.factor[0][1] + x.factor[1][1] * y.factor[1][1]) % 1000000007;
    return temp;
}
matrix qpower(int n)
{
    if(n == 1)return M;
    matrix tmp = qpower(n>>1);
    if(n&1){
        return multi(multi(tmp,tmp),M);
    }
    else return multi(tmp,tmp);
}
int fib(int num)
{
    M.factor[0][0] = 0;
    M.factor[0][1] = 1;
    M.factor[1][0] = 1;
    M.factor[1][1] = 1;

    int n = num -1;
    if(n > 0){
        matrix tmp =qpower(n);
        return tmp.factor[1][1];
    }
    else if(n == -1)return 0;
    else if(n == 0) return 1;
}
int min(int a,int b)
{
    return a > b ? b : a; 
}
int next[100010];

void ex_kmp(char *t,int len)
{
    next[0] = len - 1; 
    int j = 0;
    while( 1 + j < len && t[j] == t[1 + j]) j++;
    next[1] =  j - 1;
    int id = 1;
    for(int i = 2;i < len; i++)
    {
        int p = next[id] + id;
        int l = next [i - id];
        if(p < i)next[i] = -1;
        else next[i] = min(l, p - i);
        while(next[i] + i + 1 < len && t[next[i] + i + 1]== t[next[i] + 1]){
            next[i] ++;
        }
        if(i+next[i] > id + next[id]){
            id  = i;
        }
     } 
}
char T[100010];
int main(){

    while(~scanf("%s",T))
    {
        int len = strlen(T);
        ex_kmp(T,len);

    //  for(int i=0;i<5;i++)std::cout<<next[i]<<" ";std::cout<<std::endl;

        int sum = 0,ans = 0;
        for(int i=len-1;i>=0;--i)
        {
            sum += next[i] + 1;
            ans = (ans + fib(sum))%mod;

        //  std::cout<<"ans="<<ans<<std::endl; 
        }
        printf("%d\n",ans); 
    }
    return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值