zoukankan      html  css  js  c++  java
  • bzoj2331 [SCOI2011]地板

    2331: [SCOI2011]地板

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 1427  Solved: 601
    [Submit][Status][Discuss]

    Description

     

    lxhgww的小名叫L”,这是因为他总是很喜欢L型的东西。小L家的客厅是一个R*C的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?

    需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0。铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。

    Input

    输入的第一行包含两个整数,RC,表示客厅的大小。

    接着是R行,每行C个字符。’_’表示对应的位置是空的,必须铺地板;’*’表示对应的位置有柱子,不能铺地板。

    Output

    输出一行,包含一个整数,表示铺满整个客厅的方案数。由于这个数可能很大,只需输出它除以20110520的余数。

    Sample Input

    2 2

    *_

    __

    Sample Output

    1

    HINT

    R*C<=100

    Source

    Day1

    分析:非常神奇的一道题.

       这道题很容易看出来用插头dp做. 但是如果用左括号右括号表示插头这道题做不了,没办法转移.

       题目限制了L两端的长度不能为0,说明L一定存在一个拐点. 可以用插头表示L. 如果状态为0,则表示不存在插头;如果状态为1,则表示插头目前是一条直线;如果状态为2,则表示插头已经拐了一个弯,是一个L形了.

       考虑怎么转移. 假设当前枚举到的点是(i,j),令(i-1,j)的右插头为p,(i,j - 1)的下插头为q,(i,j)的下插头为p',(i,j)的右插头为q',分以下几种合法的情况:

       1.p = q = 0,那么可以转移到3个状态:p' = 1,q' = 0;  p' = 0,q' = 1;  p' = q' = 2. 三者的含义很容易看出来.前两个是引出一条线段,最后一个是引出一条折线段“L形”.

       2.p = 0,q = 1. 这种情况下q可以继续往下走,状态不变,p' = 1,q' = 0. 也可以往右拐,状态变成2, p' = 0,q' = 2.

       3.p = 1,q = 0,和第二种情况类似.

       4.p = 0,q = 2. 有两种选择,要么就在此停下,路径结束. 如果在最后一个非障碍点停下就可以统计答案了. 要么继续走,不能拐弯,这个时候p' = 2,q' = 0.

       5.p = 2,q = 0,和第四种情况类似.

       6.p = q = 1.两个插头结合在一起形成了一个L形,(i,j)不存在右插头和下插头,那么p' = q' = 0.

       最后统计答案找状态等于0的.

       两个坑点:1.maxn要开大!  2.n * m ≤ 100,如果m偏大要交换n,m.

       这道题挺好的,插头不仅可以表示左右括号,它作为维护连通性的工具,还可以被赋予别的意义,前提是要能够转移.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int mod = 20110520,maxn = 1000010;
    int n,m,a[110][110],now,pre,pow[110],tx,ty;
    char s[110];
    
    struct node
    {
        int head[maxn],nextt[maxn],sum[maxn],sta[maxn],tot;
        void clear()
        {
            memset(head,-1,sizeof(head));
            tot = 0;
            memset(sum,0,sizeof(sum));
            memset(sta,0,sizeof(sta));
        }
        void push(int x,int v)
        {
            int hashh = x % 50000;
            for (int i = head[hashh]; i >= 0; i = nextt[i])
            {
                if (sta[i] == x)
                {
                    sum[i] = (sum[i] + v) % mod;
                    return;
                }
            }
            sum[tot] = v;
            sta[tot] = x;
            nextt[tot] = head[hashh];
            head[hashh] = tot++;
        }
    } f[2];
    
    int turnleft(int x,int pos)
    {
        return x << pow[pos];
    }
    
    int get(int x,int pos)
    {
        return (x >> pow[pos]) & 3;
    }
    
    int del(int x,int i,int j)
    {
        return x & (~(3 << pow[i])) & (~(3 << pow[j]));
    }
    
    void solve2(int x,int y,int k)
    {
        int p = get(f[pre].sta[k],y - 1);
        int q = get(f[pre].sta[k],y);
        int staa = del(f[pre].sta[k],y - 1,y);
        int v = f[pre].sum[k];
        if (!p && !q)
        {
            if (a[x][y] == 0)
            {
                f[now].push(staa,v);
                return;
            }
            if (x < n && a[x + 1][y] == 1)
                f[now].push(staa | turnleft(1,y - 1),v);
            if (y < m && a[x][y + 1] == 1)
                f[now].push(staa | turnleft(1,y),v);
            if (x < n && a[x + 1][y] == 1 && y < m && a[x][y + 1] == 1)
                f[now].push(staa | turnleft(2,y) | turnleft(2,y - 1),v);
        }
        else if (p == 0 && q == 1)
        {
            if (x < n && a[x + 1][y] == 1)
                f[now].push(staa | turnleft(1,y - 1),v);
            if (y < m && a[x][y + 1] == 1)
                f[now].push(staa | turnleft(2,y),v);
        }
        else if (q == 0 && p == 1)
        {
            if (x < n && a[x + 1][y] == 1)
                f[now].push(staa | turnleft(2,y - 1),v);
            if (y < m && a[x][y + 1] == 1)
                f[now].push(staa | turnleft(1,y),v);
        }
        else if (p == 1 && q == 1)
            f[now].push(staa,v);
        else if (p == 0 && q == 2)
        {
            f[now].push(staa,v);
            if (x < n && a[x + 1][y] == 1)
                f[now].push(staa | turnleft(2,y - 1),v);
        }
        else if (p == 2 && q == 0)
        {
            f[now].push(staa,v);
            if (y < m && a[x][y + 1] == 1)
                f[now].push(staa | turnleft(2,y),v);
        }
    }
    
    int solve()
    {
        now = 0,pre = 1;
        f[0].clear();
        f[0].push(0,1);
        for (int i = 1; i <= n; i++)
        {
            pre = now;
            now ^= 1;
            f[now].clear();
            for (int k = 0; k < f[pre].tot; k++)
                f[now].push(turnleft(f[pre].sta[k],1),f[pre].sum[k]);
            for (int j = 1; j <= m; j++)
            {
                pre = now;
                now ^= 1;
                f[now].clear();
                for (int k = 0; k < f[pre].tot; k++)
                    solve2(i,j,k);
            }
        }
        for (int i = 0; i < f[now].tot; i++)
            if (f[now].sta[i] == 0)
                return f[now].sum[i];
        return 0;
    }
    
    int main()
    {
        freopen("test.txt","r",stdin);
        for (int i = 1; i <= 100; i++)
            pow[i] = i * 2;
        scanf("%d%d",&n,&m);
        if (n >= m)
        {
            for (int i = 1; i <= n; i++)
            {
                scanf("%s",s + 1);
                for (int j = 1; j <= m; j++)
                {
                    if (s[j] == '_')
                        a[i][j] = 1;
                    else
                        a[i][j] = 0;
                }
            }
        }
        else
        {
            for (int i = 1; i <= n; i++)
            {
                scanf("%s",s + 1);
                for (int j = 1; j <= m; j++)
                {
                    if (s[j] == '_')
                        a[j][i] = 1;
                    else
                        a[j][i] = 0;
                }
            }
            swap(n,m);
        }
        printf("%d
    ",solve() % mod);
    
        return 0;
    }
  • 相关阅读:
    设计模式(22) 策略模式
    设计模式(21) 状态模式
    设计模式(20) 观察者模式
    设计模式(19) 备忘录模式
    设计模式(18) 中介者模式
    巨杉数据库完成数亿元D轮融资,引领金融级分布式数据库发展
    ABP之IdentityServer4集成
    ABP中的多租户及多租户应用模块集成
    HDFS基础知识点总结
    如何优雅的处理SpringBoot接口的响应体
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8459779.html
Copyright © 2011-2022 走看看