对于i,a[i]即为i之后的所有a[i]的和加后缀s[0]与s[i]的最长公用前缀。
求fbi时可以先打表打出前100000个,小的直接查表,大的用矩阵快速幂求。
/*
* this code is made by 2Bpencil
* Problem: 1116
* Verdict: Accepted
* Submission Date: 2014-06-10 10:18:07
* Time: 184 MS
* Memory: 12800 KB
*/
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
#define ll long long
ll MOD=1e9+7;
ll fbi[10002];
void init()
{
fbi[0]=0;
fbi[1]=1;
fbi[2]=1;
for(int i=3;i<=10000;i++)
fbi[i]=(fbi[i-1]+fbi[i-2])%MOD;
}
struct Matrix
{
long long mat[2][2];
Matrix operator *(const Matrix &b)const
{
Matrix ret;
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
{
ret.mat[i][j] = 0;
for(int k = 0;k < 2;k++)
{
ret.mat[i][j] += (long long)mat[i][k]*b.mat[k][j]%MOD;
if(ret.mat[i][j] >= MOD)
ret.mat[i][j] -= MOD;
}
}
return ret;
}
};
Matrix pow_M(Matrix a,long long n)
{
Matrix ret;
memset(ret.mat,0,sizeof(ret.mat));
ret.mat[0][0] = ret.mat[1][1] = 1;
Matrix tmp = a;
while(n)
{
if(n&1)ret = ret*tmp;
tmp = tmp*tmp;
n >>= 1;
}
return ret;
}
long long calc(long long n)
{
if(n<=10000)
return fbi[n];
Matrix A;
A.mat[0][0] = 0;
A.mat[1][0] = 1;
A.mat[0][1] = 1;
A.mat[1][1] = 1;
A = pow_M(A,n);
return A.mat[1][0];
}
const int N = 100110;
int r[N], tx[N], ty[N], rs[N], ranks[N], sa[N], height[N], rmq[N][20]; //rs基数排序
char s[N];
bool cmp(int *r, int a, int b, int len)
{
return (r[a] == r[b]) && (r[a + len] == r[b + len]);
}
void suffix(int n, int m) //n为长度,最大值小于m
{
int i, j, p, *x = tx, *y = ty, *t;
for(i = 0; i < m; ++i)
rs[i] = 0;
for(i = 0; i < n; ++i) {
x[i] = r[i];
++rs[x[i]];
}
for(i = 1; i < m; ++i)
rs[i] += rs[i - 1];
for(i = n - 1; i >= 0; --i)
sa[--rs[x[i]]] = i;
for(j = p = 1; p < n; j <<= 1, m = p) {
for(p = 0, i = n - j; i < n; ++i)
y[p++] = i;
for(i = 0; i < n; ++i) {
if(sa[i] >= j)
y[p++] = sa[i] - j;
}
for(i = 0; i < m; ++i)
rs[i] = 0;
for(i = 0; i < n; ++i)
++rs[x[y[i]]];
for(i = 1; i < m; ++i)
rs[i] += rs[i - 1];
for(i = n - 1; i >= 0; --i)
sa[--rs[x[y[i]]]] = y[i];
t = x, x = y, y = t;
for(i = 1, p = 1, x[sa[0]] = 0; i < n; ++i) {
if(cmp(y, sa[i - 1], sa[i], j))
x[sa[i]] = p - 1;
else
x[sa[i]] = p++;
}
}
/**for(i = 0; i < n; ++i)
printf("%s\n", s + sa[i]);*/
}
void calheight(int n)
{
int i, j, k = 0;
for(i = 1; i <= n; ++i)
ranks[sa[i]] = i;
for(i = 0; i < n; ++i) {
if(k)
--k;
j = sa[ranks[i] - 1];
while(r[i + k] == r[j + k])
++k;
height[ranks[i]] = k;
}
}
void initrmq(int n)
{
int i, k;
for(i = 2; i <= n; ++i)
rmq[i][0] = height[i];
for(k = 1; (1 << k) <= n; ++k) {
for(i = 2; i + (1 << k) - 1 <= n; ++i) {
rmq[i][k] = min(rmq[i][k - 1],
rmq[i + (1 << (k - 1))][k - 1]);
}
}
}
int Log[N];
void initlog()
{
Log[0] = -1;
for(int i=1;i<N;i++){
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;}
}
int lcp(int a, int b)
{
a = ranks[a], b = ranks[b];
if(a > b)
swap(a, b);
++a;
int k = (int) Log[b - a + 1] / Log[2];
return min(rmq[a][k], rmq[b - (1 << k) + 1][k]);
}
//求两个串的最长公共子串
int main()
{
initlog();
init();
while( scanf("%s", s)!=EOF)
{
int i, l;
l = strlen(s);
for(i = 0; i < l; ++i)
r[i] = s[i];
r[l] = 0;//便于比较
suffix(l + 1, 128);
calheight(l);
initrmq(l);
long long temp=0,ans=0,a,b,c;
for(i=l-1;i>0;i--)
{
a=lcp(0,i);
temp+=a;
ans = (ans+calc(temp))%MOD;
}
temp+=l;
ans = (ans+calc(temp))%MOD;
printf("%lld\n", ans);
}
return 0;
}