CF1989E Distance to Different 题解
好题。题目要求 \(b\) 数组的数量,但 \(b\) 数组难以直接计算,而 \(b\) 数组和 \(a\) 数组的映射关系并不明显。考虑分析 \(b\) 的性质,并映射到其他数组。
我们发现,\(b\) 数组与 \(a\) 数组中元素的具体数值无关,只与 \(a\) 数组中元素的不等关系有关。因此,我们考虑把 \(b\) 数组映射到一个反映 \(a\) 数组中元素的不等关系的数组。
记 \(c_i=[a_i\ne a_{i-1}]\),特别的,不难发现 \(c_1=0\)。考虑将 \(b\) 数组映射到 \(c\) 数组。题目中要求 \(k\) 个元素至少出现一次,所以至少有 \(k-1\) 个 \(c_i\) 等于 \(1\)。若至少有 \(k-1\) 个 \(c_i\) 等于 \(1\),则一定可以构造出一个 \(a\) 数组满足条件,每次不同时换新的元素即可。因此,这个 \(c\) 数组是可行的,对应的 \(b\) 数组也是可行的。
但是,\(b\) 数组和 \(c\) 数组并不是严格的双射关系。\(c=[1,0,1]\) 和 \(c=[1,1,1]\) 时,\(b\) 数组均为 \([1,1,1]\)。因此,我们需要强制舍去其中一种情况以保证双射。由于至少有 \(k\) 个 \(c_i\) 等于 \(1\),显然应该舍去 \([1,0,1]\),这样可以获得更多的 \(c_i=1\),否则可能无法满足条件。
最后,我们使用动态规划计算满足条件的 \(c\) 数组数量。设状态 \(f[i][j][k][l]\) 表示第 \(i\) 个位置,前 \(1\) 位为 \(j\),这一位为 \(k\),一共出现 \(l\) 个 \(c_i=1\) 的情况,显然有如下转移方程:
初始 \(f[1][0][0][0]=1\),目标 \(\sum_{i=0}^{1}\sum_{j=0}^{1}f[n][i][j][k-1]\)。
时间复杂度 \(O(nk)\),代码中采用了另一种转移方式。
#include <bits/stdc++.h>
using namespace std;
long long k,n,f[200001][2][2][11],ans=0;
const long long mod=998244353;
int main()
{
scanf("%lld%lld",&n,&k);
f[1][0][0][0]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<=1;j++)
for(int l=0;l<=1;l++)
for(int p=0;p<=k-1;p++)
for(int q=0;q<=1;q++)
{
if(j==1&&l==0&&q==1)continue;
if(p+q>=k)f[i][l][q][k-1]+=f[i-1][j][l][p],f[i][l][q][k-1]%=mod;
else f[i][l][q][p+q]+=f[i-1][j][l][p],f[i][l][q][p+q]%=mod;
}
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
ans+=f[n][i][j][k-1],ans%=mod;
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号