Hadtsti
2024-11-18 16:01:35
考虑一下连通块数该怎么转化。首先明确一点就是每个连通块一定包含的是编号在一定区间内的结点,也就是如果有两个点在同一连通块中,夹在它们中间的也在这一连通块中。证明可考虑反证,若存在
也就是说我们将原序列分成了好几段,那么我们只需要在每段的左端点统计一下就可以了。现在的问题是什么情况下
那么我们直接维护只考虑
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,m,a[2010],f[2010][2010],g[2010][2010],ans;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[0][m+1]=1;
for(int i=1;i<=n;i++)
{
if(~a[i])
{
for(int j=1;j<=a[i];j++)
f[i][j]=f[i-1][j];
for(int j=a[i]+1;j<=m+1;j++)
(f[i][a[i]]+=f[i-1][j])%=mod,f[i][j]=0;
}
else
{
int s=f[i-1][m+1];
for(int j=m;j;j--)
{
f[i][j]=(1ll*f[i-1][j]*(m-j+1)+s)%mod;
(s+=f[i-1][j])%=mod;
}
}
}
g[n+1][0]=1;
for(int i=n;i;i--)
{
if(~a[i])
{
for(int j=a[i];j<=m;j++)
g[i][j]=g[i+1][j];
for(int j=0;j<a[i];j++)
(g[i][a[i]]+=g[i+1][j])%=mod,g[i][j]=0;
}
else
{
int s=g[i+1][0];
for(int j=1;j<=m;j++)
{
g[i][j]=(1ll*g[i+1][j]*j+s)%mod;
(s+=g[i+1][j])%=mod;
}
}
}
for(int i=1;i<=n;i++)
{
int s=0;
for(int j=1;j<=m;j++)
{
(s+=g[i][j])%=mod;
(ans+=1ll*f[i-1][j+1]*s%mod)%=mod;
}
}
printf("%d",ans);
return 0;
}