E. Phoenix and Computers
Posted Lnn.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Phoenix and Computers相关的知识,希望对你有一定的参考价值。
前言:写了四个小时,推出巨多种dp式子,推了半天发现基本性质给忘掉了,然后重新推才搞定。人傻了。万物皆可DP
时间复杂度为n3的DP。
先上code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,mod;
long long dp[405][202][2],mu[405][405];
int main()
cin >> n >> mod ;
for(int l = 0 ; l <= n ; ++l)
mu[l][0] = mu[0][l] = 1;
for(int l = 1 ; l <= n ; ++l)
for(int r = 1 ; r <= n ; ++r)
mu[l][r] = (mu[l-1][r]+mu[l][r-1])%mod;
dp[1][0][1] = 1;
for(int len = 2 ; len <= n ; ++len)
dp[len][0][1] = (2*dp[len-1][0][1])%mod;
for(int len = 2 ; len <= n ; ++len)
for(int num = 1 ; num <= len/2 ; ++num)/// 01,11
for(int mid = num*2 ; mid < len ; ++mid)
dp[len][num][1] = (dp[len][num][1]%mod + (((dp[mid][num][0]*dp[len-mid][0][1])%mod)*mu[mid-num][len-mid])%mod )%mod;
dp[len][num][0] = dp[len-1][num-1][1];
long long ans = 0;
for(int num = 0 ; num <= n/2 - (n%2==0) ; ++num)
ans = (ans%mod + dp[n][num][1]%mod)%mod;
cout << ans << endl ;
return 0;
E. Phoenix and Computers
题目类型:动态规划、dp。
解析:可以把需要手动的位置看成1,不需要手动的地方看成0,变成01串问题,方便处理。
第1步:观察,长度为len的01串,最多可以有len/2-(len%2==0)个0,可以枚举0的数量。
第2步:长串可以由短串转移,枚举串的长度。
第3步:一个串中,连续的1的部分的开启有固定的顺序的,简单来说必定围着(在左或者右)已经确定的顺序添加新开启的电脑,否则会意外的出现0。设dp[len][num][1]为长度len,结尾为1,有num个0的串开启顺序的方式数。则dp[len][0][1] = dp[len-1][0][1]*2 。
第4步:想转移就要把串以某种方式切块,因为连续的1有固定的方式数,可以以此把含有num个0的串,分成左边含有num个0,并且以0结尾;右边是连续的1。
dp[len][num][1] = sum(dp[mid][num][0]*dp[len-mid][1]*mu[mid][len-mid])
第5步:解释一下dp方程和mu[][],我们知道dp数组记录的是顺序数,而对于两种固定的顺序,我们要组合起来,需要知道组合后的顺序数。比如说
a:1 2 3 4 5
b:9 8 7 6 5
我们必须按照 a和b数组的顺序取数,但是每次可以从a中取,也可以从b中取,合并之后:1 9 2 8 3 7 4 6 5 5就是一个正确的例子,我们需要知道这样取的总方式数。
设mu[l][r]为a数组有l个元素,b数组有r个元素时合并后的新顺序数。则mu[l][r] = mu[l-1][r] + mu[l][r-1]。即a有6个数,b有4个数时,可以转移成(a5个,b4个)+(a6个,b3个)的状态。
dp方程的含义就是(顺序数 * 顺序数 * 两种长度的组合顺序数)
以上是关于E. Phoenix and Computers的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Global Round 14 E. Phoenix and Computers(组合数,dp)
[CF1515E]Phoenix and Computers
B. Phoenix and Beauty1400 / 构造 构造循环结