BZOJ 1210 HNOI 2004 邮递员 插头DP

75 篇文章 1 订阅
10 篇文章 0 订阅

题目有句话是不希望走更长的路,应该就是哈密尔顿回路了?然后总数乘个2?
还要注意n=1或m=1的时候并没有回路的情况。。
我太弱了,COGS上看到有人说76行即可AC,我写了个99行的。。
不过bzoj上排Rank 61。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 20001, M = 5001;
typedef long long ll;

const int power = 10000;
struct BigInteger {
    int c[10], l;
    BigInteger(){l=0;memset(c,0,sizeof c);}
    BigInteger(int a){memset(c,0,sizeof c);for(l=0;a;a/=power)c[l++]=a%power;}
    void out(){printf("%d",c[l-1]);for(int i=l-2;i>=0;i--)printf("%04d",c[i]);}
    BigInteger &operator+=(BigInteger b) {
        for(l=0;l<b.l;++l) {
            c[l] += b.c[l];
            c[l + 1] += c[l] / power;
            c[l] %= power;
        }
        for(;c[l];++l) if (c[l] >= power) {
            c[l + 1] += c[l] / power;
            c[l] %= power;
        }
        return *this;
    }
};

typedef map<ll, BigInteger>::iterator mll;
const int state[] = {0, -1, 1, 0};
int get_bit(int sta, int i) { return (sta >> (i << 1)) & 3; }
int set_bit(int &sta, int i, int x) {
    sta = (sta & ~(3 << (i << 1))) | (x << (i << 1));
}
int bracket(int sta, int i, int b) {
    int ret = i;
    for (int cnt = b; cnt; cnt += state[get_bit(sta, ret)]) ret -= b;
    return ret;
}
int left(int sta, int i) { return bracket(sta, i, state[2]); }
int right(int sta, int i) { return bracket(sta, i, state[1]); }

map<ll, BigInteger> hash[2], *cur, *last;
int bx, by, n, m;
char mp[16][16];

void update(int x, int y, int sta, const BigInteger &v) {
    int l = y == 0 ? 0 : get_bit(sta, y), s;
    int t = x == 0 ? 0 : get_bit(sta, y + 1);
    #define create(i,j) s=sta,set_bit(s,y,i),set_bit(s,y+1,j),(*cur)[s]+=v
    if (!l && !t) {
        if (x != n - 1 && y != m - 1) create(1, 2);
    } else if (!l || !t) {
        if (x < n - 1) create(l + t, 0);
        if (y < m - 1) create(0, l + t);
    } else {
        s = sta; set_bit(s, y, 0); set_bit(s, y + 1, 0);
        if (l == 1 && t == 1) set_bit(s, right(s, y + 1), 1);
        else if (l == 1 && t == 2) { if (x != bx || y != by) return; }
        else if (l == 2 && t == 1);
        else if (l == 2 && t == 2) set_bit(s, left(s, y + 1), 2);
        (*cur)[s]+=v;
    }
}

BigInteger solve() {
    int sz, i, j, rate;
    cur = hash; last = hash + 1;
    last->clear(); (*last)[0] = 1;
    for(i=0;i<n;++i) {
        rate = 2;
        for(j=0;j<m;++j) {
            cur->clear();
            for(mll k=last->begin();k!=last->end();++k) {
                if (rate == 2 && get_bit(k->first, m)) continue;
                update(i, j, k->first << rate, k->second);
            }
            rate = 0; swap(cur, last);
        }
    }
    BigInteger ans = 0;
    for(mll k=last->begin();k!=last->end();++k)
        if (k->first == 0) { ans = k->second; break; }
    return ans;
}

int main() {
    scanf("%d%d", &m, &n);
    if (m > n) swap(m, n);
    if (m == 1) puts("1");
    else {
        bx = n - 1, by = m - 1;
        BigInteger bi = solve();
        bi += bi;
        bi.out();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值