CF1515E Phoenix and ComputersAC代码+详细注释
CF1515E Phoenix and ComputersAC代码+详细注释
#include <iostream>
using namespace std;const int N = 410; // 最大电脑数量
typedef long long ll;int f[N][N]; // 动态规划数组,f[i][j]表示处理到第i台电脑,当前有j个连续段(手动打开电脑的连续段)的方案数int main(){int n, mod;cin >> n >> mod;f[0][0] = 1; // 初始状态:没有电脑时,有0个连续段,方案数为1// 动态规划过程for(int i = 0; i < n; i++) // 枚举当前已处理的电脑数for(int j = 0; j <= i; j++){ // 枚举当前连续段的数量if(!f[i][j]) continue; // 如果当前状态不可达,跳过// 情况1:新开一个连续段(单独打开一台电脑)// 新段可以插入到j+1个位置(j个段之间有j+1个空隙)(f[i+1][j+1] += (ll)f[i][j] * (j+1) % mod) %= mod;// 情况2:在当前某个连续段的一端扩展// 有j个段,每个段有左右两端可以扩展,所以乘以2j(f[i+1][j] += 2ll * f[i][j] * j % mod) %= mod;// 情况3:扩展连续段,但跳过中间一台电脑(形成间隔扩展)// 这种情况也会保持连续段数量不变(f[i+2][j] += 2ll * f[i][j] * j % mod) %= mod;// 情况4和5需要至少2个连续段才能进行if(j >= 2){// 情况4:连接两个相邻的连续段// 有j-1个空隙可以连接,每个空隙有2种连接顺序(f[i+2][j-1] += 2ll * f[i][j] * (j-1) % mod) %= mod;// 情况5:连接两个连续段,但中间跳过一台电脑// 有j-1个空隙可以这样操作(f[i+3][j-1] += (ll)f[i][j] * (j-1) % mod) %= mod;}}// 最终答案:所有电脑处理完,只剩下1个连续段的方案数cout << f[n][1];return 0;
}