wangziyue_AK
2024-11-18 15:58:29
考虑一个给定的序列有什么简洁地计算其连边后的联通块个数的方式,初步想法是建出单调栈,输出单调栈中的元素个数,但这个东西显然不好计算(而且也很假)。然后我们发现每个后缀最大值不可能向后连边(对完了),所以它肯定自成一个联通块,但打出代码会发现过不了样例,答案会大很多。仔细思考后会发现它会被形如
考虑拆贡献,对于所以
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
#define fi first
#define se second
typedef double db;
#define pb push_back
#define eb emplace_back
#define bcnt __builtin_popcount
#define TS printf("!!!tiaoshi\n")
const int p=998244353;
const int N=3005;
//inline void add(int &x,int y){ (x+=y)>=p&&(x-=p);}
inline void add(int &x,int y){ x=(x+y)%p;}
inline int jia(int x,int y){ return (x+y)>=p?x+y-p:x+y; }
inline int mul(int x,int y){ return (1ll*x*y)%p;}
inline void del(int &x,int y){ (x-=y)<0&&(x+=p);}
inline int fp(int x,int y){
if(y<0) return 0;
int res=1;
while(y){
if(y&1) res=mul(res,x);
x=mul(x,x),y>>=1;
}
return res;
}
int n,m,a[N],pre[N],suf[N],cnt[N];
void sol(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
pre[0]=m;
for(int i=1;i<=n;i++){
if(a[i]==-1) cnt[i]=cnt[i-1]+1,pre[i]=pre[i-1];
else cnt[i]=cnt[i-1],pre[i]=min(pre[i-1],a[i]);
}
for(int i=n;i;i--) suf[i]=max(suf[i+1],a[i]);
int ans=fp(m,cnt[n]);
for(int i=1;i<n;i++){
if(pre[i]<=suf[i+1]) continue;
for(int j=suf[i+1];j<pre[i];j++){
int g=1;
if(cnt[i]){
g=fp(m-j,cnt[i]);
if(j+1!=pre[i]) del(g,fp(m-j-1,cnt[i]));
}
g=mul(g,fp(j,cnt[n]-cnt[i]));
add(ans,g);
}
}
printf("%d",ans);
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int T=1;
//scanf("%d",&T);
while(T--) sol();
return 0;
}