黑暗爆炸 - 3195 奇怪的道路(状压dp)

在这里插入图片描述

题解:

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 ik i i i 的点的连边数的奇偶状态二进制压缩为 s s s,当前处理到 i i i i − k + c i-k+c ik+c 的连边。

假如 i i i i − k + c i-k+c ik+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 ik 是否是偶数条边,如果是,那么可以直接转移到 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值