简要题意

给定 \(n\)\(k\) 和值域 \([1,k]\)\(n\) 个整数 \(h_i\),求有多少个长为 \(n\) 的整数序列 \(a\) 满足值域 \([1,k]\),且 \(\sum\limits_{i=1}^n[a_i=h_i]<\sum\limits_{i=1}^n[a_i=h_{(i\bmod{n})+1}]\)。答案对 \(998244353\) 取模。

\(1 \leq n \leq 2\times 10^3,1 \leq k \leq 10^9\)

思路

小清新二维 DP 题。

\(f_{i,j}\) 为截止到第 \(i\) 位,比原来的少错 \(j\) 个数的方案数。

则动态转移方程为:

\[f_{i,j}=\begin{cases}
& kf_{i-1,j} & h_i=h_{i\bmod{n}+1}\\
& f_{i-1,j-1}+f_{i-1,j+1},(k-2)f_{i-1,j} & \text{otherwise}
\end{cases}
\]

方程解释:

  • 对于第一种情况,由于变换后对结果没有影响,所以只能从 \(f_{i-1,j}\) 转移而来, 乘上值域。
  • 对于第二种情况 \(f_{i-1,j-1}\) 是多对了一题,\(f_{i-1,j+1}\) 是少对了一题。这两种情况占了 \(2\) 个值,所以剩下的没变的 \(f_{i-1,j}\) 就只有 \(k-2\) 种了。

我们要求的是比原来多的方案数,就是 \(\sum_{i=1}^{n}{f_{n,i}}\)

边界:\(f_{0,0}=1\)

时间复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 4000+5;
const int mod = 998244353;

int F[N][N];
int n,k,h[N];

int& f(int i,int j){
    return F[i][j+n];
}
int M(const int &x){
    return (x%mod+mod)%mod;
}

signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>h[i];
    }
    f(0,0)=1;
    for(int i=1;i<=n;i++){
        for(int j=-n;j<=n;j++){
            if(h[i]==h[i%n+1]){
                f(i,j)=M(f(i-1,j)*k);
            }
            else{
                f(i,j)=M(M(f(i-1,j-1)+f(i-1,j+1))+M(f(i-1,j)*((k-2))));
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=f(n,i);
        ans=M(ans);
    }
    cout<<ans;
    return 0;
}