题意
给定一个字符集的大小 ∣ A ∣ |A| ∣A∣,可以从中选取 n n n个字符(可重复)组成一个字符串,这里规定,字符串 S S S若经过以下一系列变化所得的字符串 T T T,那么认为 S = = T S == T S==T。
- 选取有效的 b i b_i bi,令 k = b i k = b_i k=bi。
- 取字符串 S S S的前 k k k个字符组成一个字符串 S p r e S_{pre} Spre。
- 取字符串 S S S的后 k k k个字符组成一个字符串 S s u f S_{suf} Ssuf
- 将 S p r e , S s u f S_{pre},S_{suf} Spre,Ssuf各自翻转并交换组成新的字符串T。
输入规定 b 0 < b i < b i + 1 < ⋯ < b k b_0<b_i<b_{i+1} < \dots < b_k b0<bi<bi+1<⋯<bk,且 b i b_i bi可以任选多次。问能组成多少个不同的字符串。
题解
对于给定的
0
<
b
i
<
b
i
+
1
<
⋯
<
b
k
0 < b_i < b_{i+1} < \dots < b_k
0<bi<bi+1<⋯<bk,对于这些操作,现把问题转换一下,实际上就是对
[
b
k
−
1
,
b
k
)
,
[
b
k
−
2
,
b
k
−
1
)
…
,
[
0
,
b
1
)
[b_{k-1},b_{k}),[b_{k-2},b_{k-1})\dots,[0,b_1)
[bk−1,bk),[bk−2,bk−1)…,[0,b1)进行操作,每个区间之间都互不相关,可以看成独立的n个事件组成一个大事件,即对应的乘法原理,n个事件的方案相乘。设每个区间满足条件的字符串个数为
c
n
t
i
cnt_i
cnti。
c
n
t
i
cnt_i
cnti为长度为
i
i
i的字符串的对数。分为两种情况考虑,将左边的串称为L,右边称为R,设
S
=
∣
A
∣
i
S = |A|^i
S=∣A∣i
- 翻转后 R = L ,那么只有S种
- 翻转后 R != L,那么有 ∁ S 2 \complement_{S}^{2} ∁S2种
总和为
∣
A
∣
2
i
+
∣
A
∣
i
2
\frac{|A|^{2i}+|A|^i}{2}
2∣A∣2i+∣A∣i
对于每个区间都有
c
n
t
l
e
n
cnt_{len}
cntlen个字符串可选 。那么总的方案数为
c
n
t
b
1
∏
i
=
2
k
c
n
t
b
i
−
b
i
−
1
∗
∣
A
∣
n
−
2
b
k
cnt_{b_1}\prod_{i=2}^{k}cnt_{b_i-b_{i-1}} *|A|^{n-2b_k}
cntb1∏i=2kcntbi−bi−1∗∣A∣n−2bk
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 2e5+5;
ll pow_mod(ll x, ll n) {
ll res = 1;
while(n) {
if(n&1) res = res*x%mod;
x = x*x%mod;
n >>= 1;
}
return res;
}
ll n,m,A,inv;
ll b[maxn];
ll get(ll i) { // cnt_i
return (pow_mod(A,2*i)+pow_mod(A,i))%mod*inv%mod;
}
int main() {
inv = pow_mod(2,mod-2);
scanf("%lld%lld%lld", &n, &m, &A);
ll mx;
for(int i = 1; i <= m; ++i) {
scanf("%lld", &b[i]);
mx = b[i];
}
for(int i = m; i >= 1; --i)
b[i] = b[i]-b[i-1];
ll AL = pow_mod(A,n-2*mx);
ll ans = 1;
for(int i = 1; i <= m; ++i) {
ans = (ans*get(b[i]))%mod;
}
ans = ans*AL%mod;
printf("%lld\n", ans);
return 0;
}
本文深入探讨了一种基于字符串匹配的算法,通过分析字符集大小、选取字符组成字符串的方法,以及通过对字符串进行特定操作来判断两个字符串是否等价的数学问题。文章详细解释了如何计算在给定条件下能够形成的不同字符串的数量,并提供了一段C++代码实现。
1325

被折叠的 条评论
为什么被折叠?



