https://www.cometoj.com/contest/84/problem/B?problem_id=4305
思路:找规律,不难发现
S
i
S_i
Si的前半部分就是
S
i
−
1
S_{i-1}
Si−1,
S
i
S_i
Si的后半部分等于其前半部分按位取反,考虑用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示
S
i
S_i
Si的第
j
j
j个字串出现的次数,
j
=
1
j=1
j=1代表字串
00
00
00,
j
=
2
j=2
j=2代表字串
01
01
01,
j
=
3
j=3
j=3代表字串
10
10
10,
j
=
4
j=4
j=4代表字串
11
11
11,先考虑
S
i
S_i
Si的前半部分,则
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
(
j
=
1
,
2
,
3
,
4
)
dp[i][j]=dp[i-1][j](j=1,2,3,4)
dp[i][j]=dp[i−1][j](j=1,2,3,4),再考虑
S
i
S_i
Si的后半部分,根据规律,
00
00
00变成了
11
11
11,
01
01
01变成了
10
10
10,反之亦然,由此就很容易写出后半部分的递推公式,在此不再赘述。然后前半部分和后半部分拼接到一起的时候,中间的两个数字也会产生贡献,不难发现
i
i
i为奇数时为
01
01
01,否则为
11
11
11。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
int n;
ll ans[10],tmp[10];
int main()
{
scanf("%d",&n);
ans[2]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=4;j++)
tmp[j]=ans[j];
ans[1]+=tmp[4];
ans[2]+=tmp[3];
ans[3]+=tmp[2];
ans[4]+=tmp[1];
if(i&1)
++ans[2];
else
++ans[4];
for(int j=1;j<=4;j++)
if(ans[j]>=mod)
ans[j]%=mod;
}
printf("%lld %lld %lld %lld\n",ans[1],ans[2],ans[3],ans[4]);
return 0;
}