ZOJ3466-The Hive II

题意

有一个六边形格子,共 \(n\) 行,每行有 8 个位置,有一些格子不能走。求用一些环覆盖所有可走格子的方案数。\(n\le 10\)

pro

分析

插头dp,只不过是六边形上的,分奇数列和偶数列讨论,转移不太一样,但大同小异。编号需要插空,注意以下就行了。复杂度为 \(O(nm2^{2m})\)

odd_even

代码

cc_hash_table 多次用实力证明,他跑得比其他任何内置的 hash_map 都快!

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long giant;
typedef cc_hash_table<int,giant> Map;
typedef Map::iterator itt;
const int maxn=11;
const int m=8,maxm=m+1;
int n,q;
bool no[maxn][maxm];
Map f,g;
inline int get(int x,int p) {return (x>>p)&1;}
inline int mod(int x,int p,int d) {return (x&(~(1<<p)))+(d<<p);}
inline int mor(int x,int p,int d) {
    int bef=x&((1<<p)-1);
    return ((x-bef)<<d)+bef;
}
inline int mol(int x,int p,int d) { // cover the pth
    int bef=x&((1<<p)-1);
    return (((x-bef)>>(p+2))<<p)+bef;
}
int work() {
    memset(no,0,sizeof no);
    while (q--) {
        static char s[5];
        scanf("%s",s);
        no[s[0]-'A'+1][s[1]-'A'+1]=true;
    }
    f.clear(),g.clear();
    f[0]=1;
    for (int i=1;i<=n;++i) {
        f.swap(g),f.clear();
        for (itt it=g.begin();it!=g.end();++it) {
            const int &d=it->first;
            const giant &w=it->second;
            if (get(d,1)==0 && get(d,17)==0) f[d]=w;
        }
        for (int j=1;j<=m;++j) {
            f.swap(g),f.clear();
            for (itt it=g.begin();it!=g.end();++it) {
                const int &d=it->first;
                const giant &w=it->second;
                if (j&1) {
                    int a=j*2-1,t=mor(d,a+2,2),x=get(d,a),y=get(d,a+1),sum=x+y;
                    if (no[i][j]) {
                        if (!sum) f[t]+=w;
                        continue;
                    }
                    if (!sum) {
                        for (int k=0;k<4;++k) for (int r=k+1;r<4;++r) f[mod(mod(t,a+k,1),a+r,1)]+=w;
                    } else {
                        int v=mod(mod(t,a,0),a+1,0);
                        if (sum==1) for (int k=0;k<4;++k) f[mod(v,a+k,1)]+=w; else
                        if (sum==2) f[v]+=w;
                    }
                } else {
                    int a=j<<1,t=mol(d,a+2,2),u=get(d,a),x=get(d,a+1),y=get(d,a+2),z=get(d,a+3),sum=u+x+y+z;
                    if (no[i][j]) {
                        if (!sum) f[t]+=w;
                        continue;
                    }
                    if (!sum) f[mod(mod(t,a,1),a+1,1)]+=w; else {
                        int v=mod(mod(t,a,0),a+1,0);
                        if (sum==1) for (int k=0;k<2;++k) f[mod(v,a+k,1)]+=w; else
                        if (sum==2) f[v]+=w;
                    }
                }
            }
        }
    }
    printf("%lld\n",f[0]);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    while (~scanf("%d%d",&n,&q)) work();
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7511317.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值