bzoj 3195: [Jxoi2012]奇怪的道路 状压dp

来源:互联网 发布:爱上一个中国女人知乎 编辑:程序博客网 时间:2024/06/07 06:23

Description

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

Input

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

Output

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


           啊这道题真是道好题啊,推了一个小时看题解看了一个小时,大概能够理解四维的是怎么推的了。

      首先考虑状态的定义,由于我们有n个城市,j条路径,所以很容易想到前两维表示第i个城市与存在j条道路,根据一个博客的话来说,所有对立的状态都可以用0,1表示,所以我们第三位state中的0,1表示这条路的度数为奇数还是偶数,由于n非常大,所以这一维需要压缩,因为这和k条路有关,所以可以用一个长度为k+1的01串表示距离当前路k以内的路径的度数以及当前路的度数,不过无脑转移会发生混乱,所有最后还要添加一维l表示考虑转移到了state中的第l个即为考虑到第i-l个。

      接着考虑转移,对于每一种情况,我们可以考虑选或不选,如果不选,那么就可以考虑下一条边了,即dp[i][j][state][l-1]+=dp[i][j][state][l];在这里很奇怪的,我们的枚举顺序是for(int l=min(k,i-1);l>=1;l--),取最小值容易理解,因为可能不满k个,但是一个问题困扰了我很久,倒着枚举不是会使一个状态被多个状态计算,这里就要从我们的答案进行计算了,我们倒着枚举,可以起到一种前缀和的效果 ,是的dp[i][j][state][0]的答案是所有该state下的答案之和,不用再麻烦的进行计算了。接着如果选了,那么l与当前i的度数都会是奇边偶,偶变奇,即为dp[i][j+1][state^(1<<l)^1][l]+=dp[i][j][state][l]; 这个就很好理解了。最后,如何转移到下一个点呢,由于i+1的点考虑不到距离它k+1的位置,所以当距离i+1的k+1的点度数为偶数时才能转移,所以如果当前状态的第k个度数为偶数时,就可以转移到i+1与它相同的点了,由于要重新开始考虑连边,所以第四维要变成min(k,i)了

      边界条件就是考虑到第一个点什么都没连答案为1.

      答案就是dp[n][m][0][0],n个点m条边考虑完,全为偶数的状态。

      下附AC代码。

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int n,m,k;int dp[35][35][(1<<10)][10];const int mod=1e9+7;int main(){    scanf("%d%d%d",&n,&m,&k);     dp[1][0][0][0]=1;        for(int i=1;i<=n;i++)    {    for(int j=0;j<=m;j++)    {    for(int state=0;state<(1<<(k+1));state++)    {    for(int l=min(k,i-1);l>=1;l--)    {    int now=dp[i][j][state][l];    dp[i][j][state][l-1]+=now;    if(dp[i][j][state][l-1]>=mod)dp[i][j][state][l-1]-=mod;        dp[i][j+1][state^(1<<l)^1][l]+=now;    if(dp[i][j+1][state^(1<<l)^1][l]>=mod)dp[i][j+1][state^(1<<l)^1][l]-=mod;}if(((1<<k)&state)==0)dp[i+1][j][state<<1][min(k,i)]+=dp[i][j][state][0];if(dp[i+1][j][state<<1][min(k,i)]>=mod)dp[i+1][j][state<<1][min(k,i)]-=mod;}}}printf("%d\n",dp[n][m][0][0]);}




原创粉丝点击