Codeforces Global Round 14 E. Phoenix and Computers(组合数,dp)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Global Round 14 E. Phoenix and Computers(组合数,dp)相关的知识,希望对你有一定的参考价值。
灯=电脑
考虑最后的点灯状态,大概是一段连续的灯被手动打开,一个被动打开,一段连续的灯被打开…
再单独考虑打开一段连续长 k k k的灯是怎么做到的
由于不能使任何一盏灯被动打开,唯一的策略是先打开其中的任意一盏灯,之后每次都选择左边和右边任意一盏没打开的灯去打开
于是方案数为 2 k − 1 2^{k-1} 2k−1
那么定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i盏灯,手动打开了 j j j盏的方案数
f [ i ] [ j ] = ∑ k = 1 i − j f [ i − k − 1 ] [ j − k ] ∗ 2 k − 1 ∗ ( j k ) f[i][j]=\\sum\\limits_{k=1}^{i-j}f[i-k-1][j-k]*2^{k-1}*\\binom{j}{k} f[i][j]=k=1∑i−jf[i−k−1][j−k]∗2k−1∗(kj)
这个转移意思是,先枚举以 j j j结尾的最后一个连续段长为 k k k
那么这一段内部的方案为 2 k − 1 2^{k-1} 2k−1,之前部分内部的方案为 f [ i − k − 1 ] [ j − k ] f[i-k-1][j-k] f[i−k−1][j−k]
不过最后打开的这 k k k盏灯可以在任意时候被打开,也就是从 j j j个位置选 k k k个即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 409;
int n,mod,f[maxn][maxn],C[maxn][maxn],base[maxn];
void init()
{
base[0] = 1; C[0][0] = 1;
for(int i=1;i<=n;i++) base[i] = 1ll*base[i-1]*2%mod;
for(int i=1;i<=n;i++)
{
C[i][0] = 1;
for(int j=1;j<=i;j++)
C[i][j] = ( 1ll*C[i-1][j-1]+C[i-1][j] )%mod;
}
}
void upd(int &x,int y){ x = ( x+y )%mod; }
int main()
{
cin >> n >> mod;
init();
f[0][0] = 1;
for(int i=1;i<=n;i++)
{
f[i][i] = base[i-1];
for(int j=1;j<i;j++)//枚举前i个手动打开j个
{
for(int k=1;k<j;k++)//最后一段连续打开k个
upd( f[i][j],1ll*f[i-k-1][j-k]*base[k-1]%mod*C[j][k]%mod );
}
}
int ans = 0;
for(int i=1;i<=n;i++) upd( ans,f[n][i] );
cout << ans;
}
以上是关于Codeforces Global Round 14 E. Phoenix and Computers(组合数,dp)的主要内容,如果未能解决你的问题,请参考以下文章