后宫 矩阵快速幂

Posted 古时候的瘾君子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后宫 矩阵快速幂相关的知识,希望对你有一定的参考价值。

[Description]
山山是 2017 级信奥班的成员,因为良好(到大家都嫉妒的程度)的妹子缘而出名。山
山认识的妹子实在是太多,信奥班的各位纷纷猜测山山是怎么做到的。终于,Gemin 揭开了
这个秘密。原来,山山掌握了向妹子脑中写入程序的黑科技。山山向妹子脑中写入的程序是
一个只含有“N”、
“H”两种大写字母的字符串,每个大写字母代表一条指令;指令顺序执
行,并且在执行到结尾后立即返回起始位置,依此无限循环。每条指令都耗费一个指令周期
执行。
两种指令的含义如下:
“N”
:什么都不做;
“H”
:执行到这条指令的妹子 A 会找到一个新的妹子 B,并在妹子 B 的大脑中写入同一段
程序。在下一个指令周期开始时,妹子 B 会加入山山的后宫,并立即开始执行程序。
现在,山山的后宫中只有一个妹子 Eve,在第一个指令周期开始时,Eve 会从头开始执
行程序。现在请计算,在第 N 个指令周期结束时,山山的后宫里有多少妹子。为了避免答
案过大,请输出答案模上 998244353 的值。
[Input]
第一行一个整数:N。
下面一行,一个长度为 L 的、只含有“N”

“H”两种大写字母的字符串 S、代表山山会
在妹子的大脑里写入的程序。
[Output]
一行一个整数,代表在第 N 个指令周期结束时,山山的后宫里有多少妹子。
[Sample]

 


说明:什么都不做......

 


说明:虽然在第二个周期中,Eve 找到了一个新的妹子,但是新的妹子直到第三个周期的开
始才会加入后宫,因此第二个周期结束时仍然只有一个妹子。

 


[Tips]


 

我们可以把每个时刻,正在执行第几个命令的妹子数表示出来

for(int i=1;i<=n;i++)

  for(int j=0;j<len;j++)

    if(S[j]==\'N\')

      f[i+1][j+1]+=f[i][j];

    if(S[j]==\'H\')

      {

        f[i+1][j+1]+=f[i][j];

        f[i+1][0]+=f[i][j];

      }

我们看到整个递推式,其实很好用矩阵来表示和优化。

首先需要快速幂的矩阵可以确定是一个行数为了len-1,列数为len-1的矩阵,因为每个时刻的每一位数量之和上个时刻的某个数有关。

我们先可以确定矩阵最开始的雏形,由f[i+1][j+1]+=f[i][j]得出,假设了len=4:

0 0 1

1 0 0

0 1 0

而每次碰到H,只有第0行会加上f[i][j],所以我们只用在第0行加上1就可以了。

假如当前字符串是:

NH

那我们可以构造出矩阵:

0 2

1 0

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define ll long long
#define il inline
#define db double

#define mod 998244353

using namespace std;

char S[145],len;

struct mul
{
	ll a[145][145];
	mul ()
	{
		memset(a,0,sizeof(a));
	}
}hehe;

il mul chen(mul x,mul y)
{
	mul p;
	for(int i=0;i<len;i++)
		for(int j=0;j<len;j++)
			for(int k=0;k<len;k++)
				p.a[i][j]=(p.a[i][j]+x.a[i][k]*y.a[k][j])%mod;

	return p;
}

il mul pow(mul x,int b)
{
	mul tmp;
	for(int i=0;i<len;i++)
		for(int j=0;j<len;j++)
			tmp.a[i][j]=0;
	tmp.a[0][0]=1;
	while(b)
		{
			if(b&1)
				tmp=chen(x,tmp);
			x=chen(x,x);
			b>>=1;
		}
	return tmp;
}

int main()
{
	freopen("harem.in","r",stdin);
	freopen("harem.out","w",stdout);

	int n;
	cin>>n;
	
	cin>>S;
	
	len=strlen(S);

	mul T;
	T.a[0][len-1]=1;
	for(int i=1;i<len;i++)
		T.a[i][i-1]=1;

	for(int i=0;i<len;i++)
		if(S[i]==\'H\')
			T.a[0][i]++;

	mul ans=pow(T,n-1);

	int sum=0;
	for(int i=0;i<len;i++)					 
		sum=(sum+ans.a[i][0])%mod;

	printf("%d\\n",sum);
		
	return 0;
}

 

以上是关于后宫 矩阵快速幂的主要内容,如果未能解决你的问题,请参考以下文章

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

矩阵快速幂

矩阵快速幂

初步 - 矩阵快速幂

poj 3233(矩阵快速幂)

模板之矩阵快速幂(luogu P3390模板矩阵快速幂)