P5337 [TJOI2019]甲苯先生的字符串

显而易见有一个记录末尾字母的 (O(n)) 递推。

显而易见可以用矩阵快速幂优化,不妨用一个 (1 imes 26) 的矩阵维护当前 DP 值,初始化为:

[egin{bmatrix} 1&1&1cdots 1&1&1 end{bmatrix}]

构造一个 (26 imes 26) 的转移矩阵,如果 (i) 不能转移到 (j) 那么 ((j,i)=0) 否则 ((j,i)=1),这个根据矩阵乘法定义来。

然后就做完了,记得开 long long,时间复杂度 (O(log n))

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 26
#define Mod 1000000007
#define For(i,x,y)for(i=x;i<=(y);i++)
ll n;
string s1;
namespace Subtask1
{
	bool bo[N][N];
	int f[2][100005];
	void init()
	{
		int i,j,k;
		For(i,0,s1.size()-2)bo[s1[i]-'a'][s1[i+1]-'a']=1;
		For(i,0,25)f[1][i]=1;
		For(i,2,n)
		{
			For(j,0,25)
			For(k,0,25)
			if(!bo[j][k])f[i&1][k]=(f[i&1][k]+f[i&1^1][j])%Mod;
			For(j,0,25)f[i&1^1][j]=0;
		}
		For(k,1,25)f[n&1][0]=(f[n&1][0]+f[n&1][k])%Mod;
		cout<<f[n&1][0];
	}
}
namespace Subtask2
{
	struct matrix
	{
		int g[N][N];
	}a,b,c;
	matrix mul(matrix p,matrix q)
	{
		int i,j,k;
		For(i,0,25)
		For(j,0,25)
		{
			c.g[i][j]=0;
			For(k,0,25)c.g[i][j]=(c.g[i][j]+1LL*p.g[i][k]*q.g[k][j])%Mod;
		}
		return c;
	}
	void init()
	{
		int ans=0,i,j;
		For(i,0,25)
		{
			For(j,0,25)b.g[i][j]=1;
			a.g[0][i]=1;
		}
		For(i,0,s1.size()-2)b.g[s1[i]-'a'][s1[i+1]-'a']=0;
		n--;
		while(n)
		{
			if(n&1)a=mul(a,b);
			b=mul(b,b);
			n>>=1;
		}
		For(i,0,25)ans=(ans+a.g[0][i])%Mod;
		cout<<ans;
	}
}
int main()
{
//	freopen("str.in","r",stdin);
//	freopen("str.out","w",stdout);
	int i;
	cin>>n>>s1;
	if(n>100000)Subtask2::init();
	else Subtask1::init();
	return 0;
}
原文地址:https://www.cnblogs.com/May-2nd/p/14385529.html