[数据丢失]Ants

壹、题目描述 ¶

  \(\color{red}{\mathcal{The\;Portal\;Has\;Been\;Distoryed.}}\)

  在一张 \(n \times n\) 的网格图上每个格子都有一只蚂蚁。每只蚂蚁将会同时往上下左右 \(4\) 个方向中的某个方向前进一步。一个合法的方案是指所有蚂蚁移动完后仍然在网格内,且每个格子仍然有且仅有一只蚂蚁。并且,蚂蚁的对冲是被禁止的

  请统计出所有合法的方案的总数,数据范围 \(n\le 10\).

贰、题解 ¶

  第一道插头 \(\rm DP\),有被恶心到......

  考虑使用轮廓线 \(\rm DP\),定义几种插头:

  1. 空插头,值为 \(0\),就是一个空格子;

  2. 外插头,值为 \(1\),是 \(\framebox[2][]{\downarrow}\);

  3. 内插头,值为 \(2\),是 \(\framebox[2]{\uparrow}\);

  定义轮廓线表示已决策格子和未决策格子的分界线,并用一个 \(3\) 进制的数表示轮廓线上从左到右的 \(n+1\) 个插头,举个例子,就是这个样子:

[数据丢失]Ants

  然后,我们定义 \(f(i,j,S)\) 表示考虑到格子 \((i,j)\),轮廓线上的插头状态为 \(S\) 的情况,不难看出,\(S\) 是一个在 \(3\) 进制下有 \(n+1\) 位的数。

  初始状态是下面这两种状态:

[数据丢失]Ants

  前者是 \(f(1,1,(12)_3)\),后者是 \(f(1,1,(21)_3)\);

  而目标状态就是 \(f(n,n,0)\);

  考虑转移的时候就暴力讨论就可以了,考虑在 \((i,j)(j<n)\) 格子的时候,如果我们要将轮廓线扩展到 \((i,j+1)\),那么轮廓线会出现什么变化。对于所有的 \(9\) 中情况暴力讨论即可。

  对于 \(j=n\) 的情况,涉及换行,第 \(n + 1\) 个插头必须为空插头,然后在最前面插入一个空插头。弄到位运算上就是左移一位,然后去掉最高位,不过转移的前提是最高位为 \(0\).

  讨论的时候注意一下细节就行了,各种情况看代码即可。总时间复杂度 \(\mathcal O(n^23^{n+1})\). 注意开 long long.

叁、参考代码 ¶

/** @author Arextre */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
// #define NCHECK
#include <cassert>

/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */
namespace Elaina {

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#ifdef NCHECK
# define iputs(Content) ((void)0)
# define iprintf(Content, argvs...) ((void)0)
#else
# define iputs(Content) fprintf(stderr, Content)
# define iprintf(Content, argvs...) fprintf(stderr, Content, argvs)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void getmin(T& x, const T rhs) { x = min(x, rhs); }
template<class T> inline void getmax(T& x, const T rhs) { x = max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int maxn = 10;
const int maxs = 177147;

int n;
inline void input() { readin(n); }

/** @brief 1 means leaving & 2 means coming */
ll f[maxn + 5][maxn + 5][maxs + 5];
inline int trans(int s) {
    for (int ret = 0; ; ret = ret * 3 + (s % 10), s /= 10)
        if (!s) return ret;
}
int sys[20];
inline void prelude() {
    sys[0] = 1;
    rep (i, 1, 15) sys[i] = sys[i - 1] * 3;
}
inline int Lsh(int val, int pos) {
    assert(pos >= 0); assert(pos <= 15);
    return val * sys[pos];
}
inline int Rsh(int val, int pos) {
    assert(pos >= 0); assert(pos <= 15);
    return val / sys[pos];
}
int replace(int s, int p, int v) {
    assert(0 <= p); assert(p <= 15);
    int x = s / sys[p] % 3;
    return s + (v - x) * sys[p];
}
int getp(int s, int p) {
    assert(0 <= p); assert(p <= 15);
    return Rsh(s, p) % 3;
}
inline void solve() {
    f[1][1][trans(21)] = f[1][1][trans(12)] = 1;
    int U = sys[n + 1];
    rep (i, 1, n) rep (j, 0, n) rep (s, 0, U - 1) if (f[i][j][s]) {
        if (j == n) {
            if (getp(s, j)) continue; // invalid
            f[i + 1][0][Lsh(s, 1) % U] = f[i][j][s];
        }
        else {
            if (getp(s, j) == 0 && getp(s, j + 1) == 0) {
                f[i][j + 1][replace(replace(s, j, 2), j + 1, 1)] += f[i][j][s];
                f[i][j + 1][replace(replace(s, j, 1), j + 1, 2)] += f[i][j][s];
            }
            else if (getp(s, j) == 0 && getp(s, j + 1) == 1) {
                f[i][j + 1][replace(replace(s, j, 1), j + 1, 0)] += f[i][j][s];
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 1)] += f[i][j][s];
            }
            else if (getp(s, j) == 0 && getp(s, j + 1) == 2) {
                f[i][j + 1][replace(replace(s, j, 2), j + 1, 0)] += f[i][j][s];
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 2)] += f[i][j][s];
            }
            else if (getp(s, j) == 1 && getp(s, j + 1) == 0) {
                f[i][j + 1][replace(replace(s, j, 1), j + 1, 0)] += f[i][j][s];
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 1)] += f[i][j][s];
            }
            else if (getp(s, j) == 1 && getp(s, j + 1) == 1) ; // invalid
            else if (getp(s, j) == 1 && getp(s, j + 1) == 2) {
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 0)] += f[i][j][s];
            }
            else if (getp(s, j) == 2 && getp(s, j + 1) == 0) {
                f[i][j + 1][replace(replace(s, j, 2), j + 1, 0)] += f[i][j][s];
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 2)] += f[i][j][s];
            }
            else if (getp(s, j) == 2 && getp(s, j + 1) == 1) {
                f[i][j + 1][replace(replace(s, j, 0), j + 1, 0)] += f[i][j][s];
            }
            else if (getp(s, j) == 2 && getp(s, j + 1) == 2) ; // invalid
        }
    }
    writln(f[n][n][0]);
}

signed main() {
    prelude();
    input();
    solve();
    return 0;
}
上一篇:js深拷贝一个包含多个对象的数组方法


下一篇:InstantRun mode is not supported