bzoj 3195: [Jxoi2012]奇怪的道路

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

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

  

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

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int p = 1000000007;
 7 int n,m,k;
 8 int f[35][35][1<<10][10];
 9 int main()
10 {
11     scanf("%d%d%d",&n,&m,&k);
12     f[1][0][0][1]=1;
13     for(int i=1;i<=n;i++)
14     {
15         for(int j=0;j<=m;j++)
16         {
17             for(int s=0;s<1<<(k+1);s++)
18             {
19                 for(int l=1;l<=k;l++)
20                 {
21                     int tmp=f[i][j][s][l];
22                     f[i][j][s][l+1]+=tmp%=p;
23                     if(l<=i-1)f[i][j+1][s^(1<<k)^(1<<(k-l))][l]+=tmp%=p;
24                 }
25                 if((s&1)==0)f[i+1][j][s>>1][1]+=f[i][j][s][k]%=p;
26             }
27         }
28     }
29     printf("%d\n",f[n][m][0][k]);
30     return 0;
31 }

 

posted @ 2017-02-27 09:32  SD_le  阅读(557)  评论(0编辑  收藏  举报
重置按钮