UVa11741 Ignore the Blocks

UVa11741 Ignore the Blocks

  • 题目链接
  • 题意
  • 分析
  • AC 代码

题目链接

  UVa11741 Ignore the Blocks

题意

  在一个 R ×C 的网格中有 n 个黑格,其余均为白格。要求用 1×2 的骨牌覆盖所有白格(每个白格恰好被一块骨牌覆盖,且所有黑格均没有被覆盖),计算有多少种方案,并输出方案总数除以 10000007 后的余数。其中,1≤R≤4, 1≤C≤100000000, 0≤N≤100。

分析

  插头DP里面的覆盖问题,本题是UVa11270 Tiling Dominoes的升级版:1、有障碍格;2:C可达 10 8 10^8 108规模,需要借助快速矩阵幂加速。
  需要构造状态转移矩阵,首先是障碍格的矩阵,然后非障碍格的矩阵需要区分是否为列首(因此有两种),总共三种状态转移矩阵.
  一个坑点:测试数据是给出各障碍格的坐标,坐标可能重复!

AC 代码

#include 
#include 
using namespace std;

#define M 10000007
#define N 102
#define T 16

int a[T][T], b[T][T], d[T][T], e[T][T], f[T][T], g[T][T], t[T][T], x[N], y[N], s[N], r, c, m, n, h, kase = 0;

bool cmp(int i, int j) {
    return y[i] < y[j] || (y[i] == y[j] && x[i] < x[j]);
}

void copy(const int (&a)[T][T], int (&b)[T][T]) {
    for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) b[i][j] = a[i][j];
}

void mul(const int (&a)[T][T], const int (&b)[T][T], int (&c)[T][T]) {
    for (int i=0; i<m; ++i) for (int j=0; j<m; ++j) for (int k=c[i][j]=0; k<m; ++k)
        c[i][j] = (c[i][j] + a[i][k]*(long long)b[k][j]) % M;
}

void pow(int x) {
    copy(f, t);
    while (x) {
        if (x & 1) copy(e, g), mul(g, t, e);
        copy(t, g); mul(g, g, t); x >>= 1;
    }
}

int solve() {
    for (int i=0; i<n; ++i) cin >> x[i] >> y[i], s[i] = i;
    sort(s, s+n, cmp);
    m = 1<<r; h = m>>1;
    for (int i=0; i<m; ++i) {
        for (int j=0; j<m; ++j) a[i][j] = b[i][j] = d[i][j] = 0, e[i][j] = i==j;
        if (i&h) {
            a[i][(i^h) << 1] = b[i][(i^h) << 1] = d[i][(i^h) << 1 | 1] = 1;
            if (~i&1) b[i][(i^h) << 1 | 3] = 1;
        } else a[i][i<<1 | 1] = b[i][i<<1 | 1] = 1;
    }
    copy(a, f);
    for (int k=1; k<r; ++k) copy(f, g), mul(g, b, f);
    int rr = 0, cc = 0;
    for (int i=0; i<n; ++i) {
        if (cc > y[s[i]]) continue;
        if (cc < y[s[i]]) {
            if (rr > 0) {
                while (rr++ < r) copy(e, g), mul(g, b, e);
                rr = 0; ++cc;
            }
            if (cc < y[s[i]]) pow(y[s[i]] - cc);
        }
        while (rr <= x[s[i]]) copy(e, g), mul(g, rr==x[s[i]] ? d : (rr ? b : a), e), ++rr;
        rr == r ? (cc = y[s[i]] + 1, rr = 0) : cc = y[s[i]];
    }
    if (rr > 0) {
        while (rr++ < r) copy(e, g), mul(g, b, e);
        rr = 0; ++cc;
    }
    if (cc < c) pow(c - cc);
    return e[m-1][m-1];
}

int main() {
    while (cin >> r >> c >> n && r) cout << "Case " << ++kase << ": " << solve() << endl;
    return 0;
}

你可能感兴趣的:(UVa部分题目解题报告,动态规划,icpc,UVa,插头DP,覆盖模型,快速矩阵幂)