后宫
[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]
使用 dp[i][j] 代表在第 i 个指令周期中,执行第 j 条指令的妹子的数量。用转出型的
转移。
dp[i][j] 可以转移到 dp[i + 1][(j + 1) % L] ,当第 j 条指令是“ H” 时,也能转移到
dp[i + 1][0] 。观察发现 dp[i] 可以表示为 1 x L 的矩阵, dp[i] 和 dp[i + 1] 之间的转移可
以表示为边长为 L 的方阵,因此使用矩阵乘法优化即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long lol; 7 struct Matrix 8 { 9 lol a[51][51]; 10 }ans,Mat; 11 lol n,sum,Mod=998244353,l,anss; 12 char s[100005]; 13 Matrix operator*(const Matrix x,const Matrix y) 14 {int i,j,k; 15 Matrix res; 16 memset(res.a,0,sizeof(res.a)); 17 for (i=1;i<=l;i++) 18 for (j=1;j<=l;j++) 19 for (k=1;k<=l;k++) 20 res.a[i][j]+=x.a[i][k]*y.a[k][j]%Mod,res.a[i][j]%=Mod; 21 return res; 22 } 23 Matrix qpow(lol y) 24 {int i; 25 Matrix res; 26 for (i=1;i<=l;i++) 27 res.a[i][i]=1; 28 while (y) 29 { 30 if (y&1) res=res*Mat; 31 Mat=Mat*Mat; 32 y/=2; 33 } 34 return res; 35 } 36 int main() 37 {int i; 38 cin>>n; 39 cin>>s; 40 l=strlen(s); 41 for (i=0;i<l;i++) 42 if (s[i]=='H') Mat.a[i+1][1]++; 43 Mat.a[l][1]++; 44 for (i=2;i<=l;i++) 45 Mat.a[i-1][i]=1; 46 ans.a[1][1]=1; 47 Mat=qpow(n-1); 48 ans=ans*Mat; 49 for (i=1;i<=l;i++) 50 anss+=ans.a[1][i],anss%=Mod; 51 cout<<anss; 52 }