ACdream 字符串专题A Gao the string! EXKMP+矩阵快速幂

A - Gao the string!

Time Limit:  2000/1000MS (Java/Others)     Memory Limit:  128000/64000KB (Java/Others)
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] )

Input

multiple test cases.

each test case will give you a string consists of lowercase letters, the length of which is no more than 100000.

Output
ouput a number.
Sample Input
aa
Sample Output
3
Hint

样例解释如下:

对于

aa这个后缀,前缀a出现了两次,前缀aa出现了一次,总共三次

对于a这个后缀,前缀a出现了一次

所以答案是f(3) + f(1)

解法:

先用EXKMP求出s串所有后缀和自身的所有最长公共前缀,即是nxt数组。然后用dp的思想不难求出,每一个位置所有后缀出现的次数和。再用矩阵快速幂求出答案即可,并不难。

AC代码:

//
//  main.cpp
//  Gao the string!
//
//  Created by 蘇與軒 on 15/5/5.
//  Copyright (c) 2015年 蘇與軒. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <functional>
#define rep(i,a,b) for (int i=a;i<((b)+1);i++)
#define Rep(i,a,b) for (int i=a;i>=b;i--)
#define foreach(e,x) for (__typeof(x.begin()) e=x.begin();e!=x.end();e++)
#define mid ((l+r)>>1)
#define lson (k<<1)
#define rson (k<<1|1)
#define MEM(a,x) memset(a,x,sizeof a)
using namespace std;
const int N=100050;
const long long Mod=1000000007;
typedef pair<int, int> pii;
typedef long long ll;
char s[N];
ll ans;
int nxt[N];
struct Matrix {
    ll num[2][2];
    Matrix(){
        MEM(num,0);
    }
};
Matrix operator * (const Matrix &a,const Matrix &b) {
    Matrix tmp;
    rep(i,0,1)  rep(j,0,1)  rep(k,0,1)  tmp.num[j][k]+=(a.num[j][i]*b.num[i][k])%Mod;
    return tmp;
}
Matrix operator ^ (Matrix &a,ll x) {
    Matrix tmp;
    tmp.num[0][0]=1;tmp.num[1][1]=1;
    while (x) {
        if (x&1)    tmp=tmp*a;
        a=a*a;
        x>>=1;
    }
    return tmp;
}
ll getans(ll x) {
    if (x==0)   return 0;
    if (x<=2)   return 1;
    Matrix  tmp;
    tmp.num[0][0]=1;tmp.num[0][1]=1;
    tmp.num[1][0]=1;
    tmp=tmp^(x-1);
    return tmp.num[0][0]%Mod;
}
int main(int argc, const char * argv[]) {
    while (~scanf("%s",s)) {
        int l=(int)strlen(s);
        nxt[0]=l;
        int p=0;
        while (p+1<l&&s[p]==s[p+1]) p++;
        nxt[1]=p;
        int k=1,L;
        rep(i,2,l-1) {
            p=k+nxt[k]-1,L=nxt[i-k];
            if (i+L<=p) nxt[i]=L;
            else {
                int j=p-i+1;
                if (j<0)    j=0;
                while (i+j<l&&s[i+j]==s[j]) j++;
                nxt[i]=j;k=i;
            }
        }
        Rep(i,l-1,0)    nxt[i]+=nxt[i+1];
        ans=0;
        rep(i,0,l-1)    ans=(ans+getans(nxt[i]))%Mod;
        printf("%lld\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值