acdream 1116 Gao the string! (扩展kmp,dp思想,矩阵优化)

题意:

题目要求每个后缀能包含多多少前缀,只不过这个数作为斐波那契的下标,求出对应斐波那契的和。

题解:

首先对于要计算出对应的后缀包含多少前缀,如果单单指考虑这样某个后缀能和多少前缀重合,可以通过扩展kmp求得。因为是求后缀对应的某个子串能包含多少前缀,因此要从后往前递推累加,然后同时计算对应的斐波那契数。开始的时候打斐波那契数的表,想找到循环节通过模处理,但是太大了,打不了,开始还因为这个re了几发,其实算了下复杂度2^3*log(n)完全可以用矩阵乘法搞,然后就O(nlong(n))水水的过了。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void cmax(int& a, int b){ if (b>a)a = b; }
void cmin(int& a, int b){ if (b<a)a = b; }
void cmax(ll& a, ll b){ if (b>a)a = b; }
void cmin(ll& a, ll b){ if (b<a)a = b; }
void add(int& a, int b, int mod){ a = (a + b) % mod; }
void add(ll& a, ll b, ll mod){ a = (a + b) % mod; }
const int oo = 0x3f3f3f3f;
const ll OO = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1000000007;
const int maxn = 110000;
char s[maxn];
ll Next[maxn];

struct Marix{
	ll a[2][2];
	Marix(){ memset(a, 0, sizeof a); }
};

Marix Mutil(const Marix &a, const Marix &b){
	Marix c;
	for (int i = 0; i < 2; i++){
		for (int j = 0; j < 2; j++){
			for (int k = 0; k < 2; k++)
				c.a[i][j] += a.a[i][k] * b.a[k][j];
			c.a[i][j] %= MOD;
		}
	}
	return c;
}

ll Pow(Marix a, ll k){
	Marix ans;
	ans.a[0][0] = ans.a[1][1] = 1;
	while (k){
		if (k & 1) ans = Mutil(a, ans);
		a = Mutil(a, a);
		k >>= 1;
	}
	return ans.a[1][0];
}

void get_extend(char T[], int len){
	int k = 0;
	Next[0] = len;
	while (k<len - 1 && T[k] == T[k + 1])k++;
	Next[1] = k;
	k = 1;
	for (int i = 2; i<len; i++)
	{
		int p = k + Next[k] - 1, L = Next[i - k];///p表示目前匹配的最大长度
		if (i + L - 1 >= p)///大于,要更新
		{
			int j = max(p - i + 1, 0);
			while (i + j<len&&T[i + j] == T[j])j++;
			Next[i] = j;
			k = i;
		}
		else Next[i] = L;
	}
}


int main(){
	Marix a;
	a.a[0][0] = 1; a.a[0][1] = 1;
	a.a[1][0] = 1; a.a[1][1] = 0;
	while (scanf("%s", s) != EOF){
		int len = strlen(s);
		get_extend(s, len);
		ll ans = Pow(a, Next[len - 1]);
		for (int i = len - 2; i >= 0; i--){
			Next[i] += Next[i + 1];
			ans += Pow(a, Next[i]);
			ans %= MOD;
		}
		cout << ans << endl;
	}
	return 0;
}



你可能感兴趣的:(acdream 1116 Gao the string! (扩展kmp,dp思想,矩阵优化))