【300iq Contest 1 K】Knowledge 题解

题目大意

  给定一个长度为 $n$ 的、仅含 a,b 的字符串 $s$,每次可以对 $s$ 做下列操作:

  • 在任意位置添加或删除 aa;
  • 在任意位置添加或删除 bbb;
  • 在任意位置添加或删除 ababab。

  问 $s$ 能变成多少种长度为 $x$ 的字符串,答案模 $998244353$。

  $n \le 3 \times 10^5,\ x \le 10^9$

题解

  官方题解直接抛出了个 Tetrahedral symmetry。。。这玩意到底是怎么跟四面体旋转扯上关系的啊

  以下是比较算法竞赛的思路。

  就是每个字符串的最小表示竟然是唯一的。具体来说,给定一个字符串,它能唯一转化成一个长度在 4 以内的串。
  而这种基础串只有 12 种。

  证明的话因为题解啥也没写,不知道这鬼东西是不是有什么绝妙的证明,所以我只能脑补一个马后炮的归纳证法。首先手撸长度为 5 以内的所有串,发现它们确实能且仅能转化成 12 种基本串,然后归纳法,假设串长为 $n$ 时结论成立,串长为 $n+1$ 时可以先对前 $n$ 位做操作使其转化成 4 以内的基本串,然后再加上第 $n+1$ 位的字符形成一个长度为 5 的串,由手撸结果,它能转化为基本串。

  这个归纳证明也给出了求一个串转化成基本串(即最小表示)的方法:从左往右一位一位地添加字符,若当前字符串能转化成基本串,则转化。只需一开始把手撸的长度在 5 以内的转化规则全部记在 map 里即可。

  最后只需一个矩阵快速幂求出各种基本串在长度为 $x$ 时有多少对应的字符串即可。具体来说,做一个转移矩阵 $C$,$C_{ij}$ 表示基本串 $i$ 在末尾添加一个字符(a 或 b)转化成基本串 $j$ 的方案数。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxtot=13;
const LL mo=998244353;

int n,x;
string s;

unordered_map<string,int> M;
unordered_map<string,string> trans;
int tot;
void add(string s) {M[s]=++tot;}
int getMinStr(string s)
{
string t;
for(auto c:s)
{
t+=c;
if (trans.count(t)) t=trans[t];
}
return M[t];
}

struct ARR{
LL n[maxtot][maxtot];
} re;
ARR operator * (const ARR &a,const ARR &b)
{
fo(i,1,tot)
fo(j,1,tot)
{
re.n[i][j]=0;
fo(k,1,tot) (re.n[i][j]+=a.n[i][k]*b.n[k][j])%=mo;
}
return re;
}

ARR C,Ans;
void Pow(ARR x,int y)
{
for(; y; y>>=1, x=x*x) if (y&1) Ans=Ans*x;
}

void Pre()
{
add("");
add("a");
add("ab");
add("aba");
add("abb");
add("b");
add("ba");
add("bab");
add("babb");
add("bb");
add("bba");
add("bbab");

trans["aa"]=trans["bbb"]="";
trans["abaa"]="ab";
trans["abab"]="bba";
trans["abba"]="bab";
trans["abbb"]="a";
trans["baa"]="b";
trans["baba"]="abb";
trans["babba"]="bbab";
trans["babbb"]="ba";
trans["bbaa"]="bb";
trans["bbaba"]="babb";
trans["bbabb"]="aba";

for(auto p:M)
{
C.n[p.second][getMinStr(p.first+'a')]++;
C.n[p.second][getMinStr(p.first+'b')]++;
}
}

int main()
{
Pre();

cin >> n >> s >> x;

Ans.n[1][1]=1;
Pow(C,x);

printf("%lld\n",Ans.n[1][getMinStr(s)]);
}