非常好的dp,非常考dp的能力

很显然是个计数问题,那么很显然要么是排列组合,要么是递推,这道题很显然递推的面更大一些。

那么我们来设计一下状态:

设状态f[i][j][k][p]表示目前到了第i个点,这i个点中有j个白点是奇数条好的路径的结尾,k个黑点是奇数条好的路径的结尾,p个白点是偶数条好的路径的结尾的方案数

可能这个状态本身不是特别好懂,我们详细解释一下:

这样的图的个数会取决于好的路径的条数,而好的路径的条数又可以分成两类:以黑点为结尾和以白点为结尾

那么对于每一个黑点或白点,他只有两种可能:有奇数条好的路径在这结尾和有偶数条好的路径在这结尾。

这样我们就将整个图的点分为了4类:白点是奇数条好的路径的结尾,黑点是奇数条好的路径的结尾,白点是偶数条好的路径的结尾,黑点是偶数条好的路径的结尾。

我们将其中三种扔进状态里,而第四个就可以算出来。

接着我们考虑转移:

分类转移:如果一个节点是白色,那么一个合法的路径一定会从上一个黑点转过来。

而且如果想要影响这个白点奇偶性,上面一定会连上一个奇数黑点,因为偶数黑点对这个白点的奇偶性没有影响。

我们讨论这个白点是奇数白点还是偶数白点:如果这个白点是奇数白点,那么从上面的奇数黑点转过来时,要连1个,3个...奇数个,这样才能保证这个白点是奇数的。

那么如果设之前奇数黑点的数量为k,总方案数即为

利用这一点,乘原来方案数转移即可

那么这个白点是偶数白点的转移也同理,总方案数即为

同理转移即可

最后,考虑其他点:由于别的点对这个白点的奇偶性没有影响,所以对于别的点可以随便连,也就是2^别的点的个数,乘这个东西即可

那么黑点也就同理了。

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define mode 1000000007
using namespace std;
ll dp[55][55][55][55];//到了第几个点,奇数白点,奇数黑点,偶数白点
int n,typ;
int c[55];
ll mul[55];
int main()
{
scanf("%d%d",&n,&typ);
mul[0]=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);//0黑1白-1任意
mul[i]=(mul[i-1]<<1)%mode;
}
ll ret=0;
if(c[1]==0||c[1]==-1)
{
dp[1][0][1][0]=1;
if(typ==1&&n==1)
{
ret++;
}
}
if(c[1]==1||c[1]==-1)
{
dp[1][1][0][0]=1;
if(typ==1&&n==1)
{
ret++;
}
}
for(int i=2;i<=n;i++)
{
for(int j=0;j<=i;j++)//奇数白
{
for(int k=0;k+j<=i;k++)//奇数黑
{
for(int p=0;j+k+p<=i;p++)//偶数白
{
int t=i-j-k-p;//偶数黑
if(c[i]==1||c[i]==-1)
{
ll s=0;
if(j+p)
{
if(j)
{
if(!k)
{
s+=dp[i-1][j-1][k][p];
}else
{
s+=mul[k-1]*dp[i-1][j-1][k][p]%mode;
}
s%=mode;
}
if(p)
{
if(k)
{
s+=mul[k-1]*dp[i-1][j][k][p-1]%mode;
}
s%=mode;
}
}
s*=mul[j+p+t-1];
s%=mode;
dp[i][j][k][p]+=s;
dp[i][j][k][p]%=mode;
}
if(c[i]==0||c[i]==-1)
{
ll s=0;
if(k+t)
{
if(k)
{
if(!j)
{
s+=dp[i-1][j][k-1][p];
}else
{
s+=mul[j-1]*dp[i-1][j][k-1][p]%mode;
}
s%=mode;
}
if(t)
{
if(j)
{
s+=mul[j-1]*dp[i-1][j][k][p]%mode;
}
s%=mode;
}
}
s*=mul[k+p+t-1];
s%=mode;
dp[i][j][k][p]+=s;
dp[i][j][k][p]%=mode;
}
if(i==n)
{
if((j+k)%2==typ)
{
ret+=dp[i][j][k][p];
ret%=mode;
}
}
}
}
}
}
printf("%lld\n",ret);
return 0;
}

CF979E的更多相关文章

  1. ZR8.2 DP

    DP 1CF1101D 我们发现,最终答案一定和质因数有关 我们发现\(w_i <= 2*10^5\)级别的树,他的素因子的个数不会非常多(\(<=10\)) 然后我们就设 gcd是\(d ...

随机推荐

  1. 【blog】SpringBoot的可执行文件如何在Linux中后台运行(待补充...)

    参考链接 linux下利用nohup后台运行jar文件包程序:http://blog.csdn.net/tang9140/article/details/38899345

  2. mysql 案例 ~超时时间设置

    一 简介:今天咱们来谈谈mysql的连接时间与会话关系二 分类  mysql会话分类  1 程序连接session(最主要的)  2 binlog连接session(复制+canal消费)  3 ro ...

  3. 《Java编程思想第四版》附录 B 对比 C++和 Java

    <Java编程思想第四版完整中文高清版.pdf>-笔记 附录 B 对比 C++和 Java “作为一名 C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且 Java 的语法无疑是 ...

  4. 解决安装YouCompleteMe与Vim版本不兼容问题

    用vim 7.4.4版本装YouCompleMe的时候提示这样的信息: YouCompleteMe unavailable: requires Vim 7.4.1578+.明明版本比它要求的还高,居然 ...

  5. tp5.0 SHOW COLUMNS FROM 生成数据表字段缓存

    TP5.0 生成数据表字段缓存 =控制台执行以下命令= 1.生成指定数据库的所有表字段缓存 php think optimize:schema --db databaseName 2.生成指定数据表的 ...

  6. 【MongoDB】 Failed to connect to 127.0.0.1:27017, reason: Connection refused

    由于项目需要,在一台虚拟机上安装了MongoDB,但是在启动的时候,出现如下错误: [root@localhost bin]# ./mongo MongoDB shell version v3.4.0 ...

  7. 关于Mac或Linux下GO的Permission denied提示错误

    有时候当你下载第三方库的时候,编译时会提示Permission denied 权限不足, 出现这种错误因为权限不够.其中一种办法是需要把你项目目录和go的pck.bin权限放开. chmod -R 7 ...

  8. 【转】python之random模块分析(一)

    [转]python之random模块分析(一) random是python产生伪随机数的模块,随机种子默认为系统时钟.下面分析模块中的方法: 1.random.randint(start,stop): ...

  9. Euclideanloss_layer层解析

    这里说一下euclidean_loss_layer.cpp关于该欧式loss层的解析,代码如下: #include <vector> #include "caffe/layers ...

  10. VIsual Studio编译OpenCV:无法打开python27_d.lib(python36_d.lib)的问题

    原文地址:http://blog.csdn.net/Chris_zhangrx/article/details/78947526 在用 VS2015 编译 Debug 版的 openCV 源码时,最后 ...