题目传送门https://vjudge.net/problem/CSES-1746#author=GPT_zh
解题思路
这是一道 DP 题……
首先,很容易想到设 表示前
个数,最后一个数为
的合法序列的总数。
对于每一个 ,分两种情况讨论:
若 ,那么,我们可以直接从前面的
到
的范围转移。
若 ,那么,我们可以枚举上一个数
,然后对这个数的贡献就是在
和
之间的贡献。
当然,你会发现:每次转移都只和 有关,所以可以滚动数组优化空间。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[100002];
int f[2][101];
const int mod=1e9+7;
int ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
if(!a[1])
for(int i=1;i<=m;i++)
f[1][i]=1;
else
f[1][a[1]]=1;
int k;
int t1,t2;
for(int i=2;i<=n;i++)
{
k=i%2;
for(int j=1;j<=m;j++)
f[k][j]=0;
if(a[i])
{
f[k][a[i]]=0;
for(int j=max(1,a[i]-1);j<=min(m,a[i]+1);j++)
{
(f[k][a[i]]+=f[k xor 1][j])%=mod;
// if(i==3)
// {
// cout<<(k xor 1)<<" "<<j<<endl;
// }
}
}
else{
for(int j=1;j<=m;j++)
{
if(f[k xor 1][j])
{
for(int l=max(1,j-1);l<=min(m,j+1);l++)
(f[k][l]+=f[k xor 1][j])%=mod;
}
}
}
// for(int j=0;j<=m;j++)
// {
// cout<<i<<" "<<j<<" "<<k<<" "<<f[k][j]<<endl;
// }
}
if(a[n])
cout<<f[n%2][a[n]];
else{
for(int j=1;j<=m;j++)
(ans+=f[n%2][j])%=mod;
cout<<ans;
}
}