3195: [Jxoi2012]奇怪的道路

Description

小宇从历史书上了解到一个古老的文明。这个文明在各个方面高度发达,交通方面也不例外。考古学家已经知道,这个文明在全盛时期有n座城市,编号为1..n。m条道路连接在这些城市之间,每条道路将两个城市连接起来,使得两地的居民可以方便地来往。一对城市之间可能存在多条道路。
据史料记载,这个文明的交通网络满足两个奇怪的特征。首先,这个文明崇拜数字K,所以对于任何一条道路,设它连接的两个城市分别为u和v,则必定满足1 <=|u - v| <= K。此外,任何一个城市都与恰好偶数条道路相连(0也被认为是偶数)。不过,由于时间过于久远,具体的交通网络我们已经无法得知了。小宇很好奇这n个城市之间究竟有多少种可能的连接方法,于是她向你求助。
方法数可能很大,你只需要输出方法数模1000000007后的结果。

Input

输入共一行,为3个整数n,m,K。

Output

输出1个整数,表示方案数模1000000007后的结果。

Sample Input

【输入样例1】
3 4 1
【输入样例2】
4 3 3

Sample Output

【输出样例1】
3
【输出样例2】
4

HINT

【数据规模】

100%的数据满足1<= n <= 30, 0 <= m <= 30, 1 <= K <= 8.

【题目说明】

两种可能的连接方法不同当且仅当存在一对城市,它们间的道路数在两种方法中不同。

在交通网络中,有可能存在两个城市无法互相到达。


  可能我的大多数前辈都没有做过这道题,不然应该还是会细细深思的。网上很多题解都没有开滚动,而且开了个四维的数组,空间与时间都多了一个常数k。而POPOQQQ空间上开了三维,时间上却慢了许多。他说:“标解不是这个- - 状态多了一维,代替掉了sta2的枚举,具体做法不大清楚- - 反正比这个快了40倍- -”

  

  我来说说我的想法吧。仨打表的,还是比我强啊。

  我的空间是2*m*2^(k+1)的(2是滚动的),时间是n*(m*2^k+k*m*2^(k+1))的。在网上,我看见大多数空间与时间都多了一个常数k。也可能是我眼拙或是太没有耐心了,没有看见更快的。

  而这不只是空间与时间的区别。我做过的状压题不多,但这道题的实现确实是最简单的。而有一篇博客如是说:“细节特别特别多!!! 要看代码好好思考!!!”也有人说:“因为这道题实现起来有一些复杂,所以是一道当之无愧的好题。”

  这个常数的道理在什么地方?其实想起来也很简单。借用一份题解,谢谢博主SD_le

  第一眼看到题比较裸的状压dp就是f[i][j][s]表示考虑到第i个点,连了j条边,i和i左边k个点奇偶性状态为s的方案数,然后枚举i和谁连边向j+1转移,每个s再向i+1转移。

  写完后发现这个做法有bug,因为同一个状态因为i向外连边的顺序不同而被重复记数了。比如:

  

  第一个状态就在第四个状态中被重复记了两次,所以我们在加一位状态l,表示i正准备和i-l连边,这样i的边就是从左往右连的,就不会重复记数了。

  只要知道状压是什么(PS:我当然知道啊不就是状态压缩类动态规划吗),应该是很好列出来三维对应的含义的。但是,当你真正做出来时,也常常会发现上述的那个bug。有可能从一点i连到前面那几个点的边发生了重复。这就看上去很不清真了。但是,当对DP的认识上升到了沿拓扑序转移状态这样的“境界”时,你就会发现,i连向相同一个点的边就很像背包问题中的一件物品,每一件物品都是不限量的(只是最终要求了奇偶)。想一想,我们的完全背包统计方案时并没有多开一维,但绝对不会重复计数的。原因很简单,在做背包问题时,各个物品的选取存在严格顺序,不存在“选了几个物品a,又选了一点别的,再去选了几个物品a”的情况。只要能想到这里,如何解决就不是很难了。应当严格区分出各个物品,在每一个物品内部进行顺推(因为是完全背包)。

 /**************************************************************
Problem: 3195
User: Doggu
Language: C++
Result: Accepted
Time:68 ms
Memory:960 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <algorithm>
const int M = + ;
const int K = ;
const int MOD = 1e9+;
int n, m, k, f[][M][<<K], cur, lm, lim, pow[K];
inline void add(int &a,int b) {a=a-MOD+b>?a-MOD+b:a+b;}
int main() {
scanf("%d%d%d",&n,&m,&k);pow[]=;for( int i = ; i <= k; i++ ) pow[i]=pow[i-]<<;
f[cur][][]=;lim=<<(k+);lm=<<k;
for( int i = ; i <= n; i++ ) {
cur^=;memset(f[cur],,sizeof(f[cur]));
for( int j = ; j <= m; j++ ) for( int st = ; st < lm; st++ ) f[cur][j][st<<]=f[cur^][j][st];
int bound=std::min(k,i-);for( int bit = ; bit <= bound; bit++ ) for( int j = ; j < m; j++ ) for( int st = ; st < lim; st++ ) add(f[cur][j+][st^^pow[bit]],f[cur][j][st]);
}
printf("%d\n",f[cur][m][]);
return ;
}

3195

最新文章

  1. c++源文件后缀名
  2. eval的对于验证数学公式的用处
  3. beanFactoory介绍
  4. eclipse安装ermaster建模插件
  5. 在MAC下调试运行暗黑全世界客户端及部分代码注解(基于Firefly)
  6. 转载:一句代码改变Swing难看的字体
  7. BaseAdapter 注意的关键点!
  8. Js-Html 前端系列--checkbox
  9. VMware 下的CentOS6.7 虚拟机与Windows7通信
  10. css流式布局
  11. u盘安装centos7.6 最新版本
  12. Java9+版本中,Interface的内容
  13. kindeditor用法简单介绍(转)
  14. jquery的$(document).ready()与js的window.onload区别
  15. 分享一个CSS+JavaScript框架materializecss
  16. 给iOS开发新手送点福利,简述UIScrollView的属性和用法
  17. Luogu 2801 教主的魔法 | 分块模板题
  18. Mysql数据库一个表字段中存了id,并以逗号分隔,id对应的详细信息在另一个表中
  19. 转载:Logistic回归原理及公式推导
  20. [Android Tips] 29. 如何判断当前编译的是哪个 Flavor ?

热门文章

  1. WPF编程,通过Double Animation动态缩放控件的一种方法。
  2. adb连接手机的两种方式
  3. Easy Pipeline,一种轻量级的Python Pipeline库
  4. 【ORACLE】碎片整理
  5. 【拾遗】理解Javascript中的Arguments
  6. 【DDD】业务建模实践 —— 发布帖子
  7. Dictionary 对象
  8. RabbitMq基础教程之基本概念
  9. python图像处理 模式转化简单总结
  10. Mac OS系统 sublime text3 常用快捷键记录