经典
我们先来解决最经典的圆环染色问题。
一个环上有\(n\)个点,每个点染为\(m\)种颜色之一,要求相邻两点颜色不同。求可行的方案数。
——《彩色圆环(circle)》命题报告,吴佳俊
那么,设\(f[i][0/1]\)表示当前正在决定第\(i\)位的颜色,且要求该颜色是否(\(0/1\))与第\(1\)位颜色相同。
对于\(f[i][1]\)没啥好决定的,第\(i\)位必须与第\(1\)位相同,所以系数是\(1\)。
对于\(f[i][0]\)分两种情况,一种前接\(f[i-1][1]\),这时第\(i-1\)位颜色与第\(1\)位颜色相同,有\((m-1)\)种颜色供第\(i\)位选择。一种是前接\(f[i-1][0]\),第\(i-1\)位与第\(i\)位不同了,第\(i\)位不能与其中任一相同,只有\((m-2)\)种可以选。
\[\begin{aligned}
f[i][0] &= (m-2) f[i-1][0] + (m-1) f[i-1][1] \\
f[i][1] &= f[i-1][0]
\end{aligned}
\]
初始状态很重要,保险的定义应该从\(2\)开始,但是根据意义从\(1\)开始也无妨。
#include
#include
#include
using namespace std;
typedef long long ll;
const ll MOD=998244353;
const ll MXN=1E7+5;
ll f[MXN][2];
int main(){
ll N,M;scanf("%lld%lld",&N,&M);
f[1][0]=0,f[1][1]=M;
for(ll i=2;i<=N;i++){
f[i][0]=((M-1)*f[i-1][1]+(M-2)*f[i-1][0])%MOD;
f[i][1]=f[i-1][0]%MOD;
}
cout<
return 0;
}
上面这个dp其实还可以更优ÿ