题解:AT_abc457_f [ABC457F] Second Gap
RainFestival · · 题解
Update on 2026/05/12: 代码贴错了,现在已经修正。
题意:对于一个长度为
我们先把序列反转一下,那么问题就变成前缀了,看起来舒服一点(笑)。
我们考虑
考虑进行优化。首先考虑缩减状态空间。我们发现次大值的位置不重要。因为在前两种情况中,次大值会被抛弃;在最后一种情况中,不会更新结果。因此我们永远不会利用到次大值的位置信息。这压根就得到了一个
然后我们考虑一下转移。记
-
-
-
如果
d_i=d_{i+1} ,那么有\forall k\in \{1,\cdots,i\},f_{i+1,k}\leftarrow f_{i+1,k}+f_{i,k}\times (i-1) 。
然后我们考虑
这个转移是好实现的。需要的转移数是
::::info[时间复杂度证明]
我们考虑
由于笔者使用
以下给出笔者的
::::info[代码]
#include<cstdio>
#include<algorithm>
#include<map>
const int mod=998244353;
int n,f[200005];
long long inv[200005],fac[200005],s=0;
std::map<int,long long> dp;
long long fp(long long x,int y){return !y?1:(y&1?x:1)*fp(x*x%mod,y/2)%mod;}
int main()
{
scanf("%d",&n);
for (int i=2;i<=n;i++) scanf("%d",&f[i]);
std::reverse(f+2,f+n+1);
if (f[2]!=1) return puts("0"),0;
for (int i=1;i<=n;i++) inv[i]=fp(i,mod-2);
fac[0]=1;for (int i=1;i<=n-2;i++) fac[i]=fac[i-1]*i%mod;
dp[1]=dp[2]=1;
for (int i=2;i<n;i++)
{
long long val=0;
if (f[i+1]<(i+1)) val=dp[(i+1)-f[i+1]]*inv[i-1]%mod;
if (f[i+1]!=f[i]) dp.clear();
dp[(i+1)-f[i+1]]=(dp[(i+1)-f[i+1]]+val)%mod;
dp[i+1]=(dp[i+1]+val)%mod;
}
for (int i=1;i<=n;i++) s=(s+dp[i])%mod;
s=s*fac[n-2]%mod;
printf("%lld\n",s);
return 0;
}
::::