题解:
设 d p [ i ] [ j ] [ s ] [ c ] dp[i][j][s][c] dp[i][j][s][c]表示处理到第 i i i个点,已经连了 j j j条边,第 i − k i-k i−k 到 i i i 的点的连边数的奇偶状态二进制压缩为 s s s,当前处理到 i i i 与 i − k + c i-k+c i−k+c 的连边。
假如 i i i 与 i − k + c i-k+c i−k+c 不连边,那么直接转移到状态 d p [ i ] [ j ] [ s ] [ c + 1 ] + = d p [ i ] [ j ] [ s ] [ c ] dp[i][j][s][c+1]+=dp[i][j][s][c] dp[i][j][s][c+1]+=dp[i][j][s][c] 。
若连边,则转移到状态 d p [ i ] [ j + 1 ] [ s ⨁ ( 1 < < k ) ⨁ ( 1 < < c ) ] [ c ] + = d p [ i ] [ j ] [ s ] [ c ] dp[i][j+1][s \bigoplus (1<<k) \bigoplus (1<<c)][c]+=dp[i][j][s][c] dp[i][j+1][s⨁(1<<k)⨁(1<<c)][c]+=dp[i][j][s][c]。这里没有转移到 c + 1 c+1 c+1,因为两个点之间可以有多条边。
最后处理完k个点后,判断 i − k i-k i−k 是否是偶数条边,如果是,那么可以直接转移到 d p [ i + 1 ] [ j ] [ s > > 1 ] [ 0 ] dp[i+1][j][s>>1][0] dp[i+1][j][s>>1][0] 。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=(1<<9);
const int inf=0x3f3f3f3f;
ll dp[35][35][MAXN][10];
int main()
{
int n,m,k;
cin>>n>>m>>k;
dp[2][0][0][0]=1;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int s=0;s<(1<<(k+1));s++)
{
for(int c=0;c<k;c++)
{
if(dp[i][j][s][c])
{
dp[i][j][s][c+1]+=dp[i][j][s][c]%mod;
dp[i][j][s][c+1]%=mod;
if(j<m&&i-k+c>=1)
{
dp[i][j+1][s^(1<<k)^(1<<c)][c]+=dp[i][j][s][c]%mod;
dp[i][j+1][s^(1<<k)^(1<<c)][c]%=mod;
}
}
}
if(!(s&1)&&dp[i][j][s][k]) dp[i+1][j][s>>1][0]=dp[i][j][s][k];
}
}
}
cout<<dp[n+1][m][0][0]<<endl;
}