[HDU 5079][2014 Asia AnShan Regional Contest]Square(DP套DP)

2023-11-18

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=5079

题目大意

给你一个 nn(n8) 的棋盘,上面有一些格子必须是黑色,其它可以染黑或者染白,对于一个棋盘,定义它的优美度为它上面最大的连续白色子正方形的边长,对于每个 0in ,问有多少种染色方案使得棋盘的优美度为 i ?

题目来源

2014 Asia AnShan Regional Contest,by WJMZBMR.

题目思路

比较显然的是这个题可以拆成n+1问来处理,每一问相当于求出优美度为 i 的方案数,不过比较逗的是我们需要先求出最大白色正方形边长小于i的方案数,再求其补集得到最大xxxx大于等于 i 的方案数ans[i],最后 ans[i+1]ans[i] 就是优美度为 i 的方案数。
这里写图片描述
真是蛋疼到极点。。。不过经过上面的思考,问题就能简化为求出最大白色正方形边长小于sz的方案数。不妨用 dp[i][sta] 来表示DP到了第 i 行,该行状态为sta的方案数。
这里需要解释一下每一行的状态,它实际上就是一个最小表示法的数字,这个数字中的第 i 位表示的是该行从第i个格子到第i+sz-1个格子中每个格子往上走的连续白格子个数的最小值。
注意我上面加的粗体,是为了方便断句,避免由断句引起歧义。
那么我们就能从第i1dp[i1][sta]推出第 idp[i][newsta] newsta 是对第 i 行的染色情况进行暴力枚举后,去掉不合法的情况(出现了最大正方形边长大于等于i的情况)后得到的。
很显然DP方程为 dp[i][newsta]=dp[i1][sta]
然后再求 dp[i][j] 的补集,即最大xxxx大于等于i的方案数,暂且叫 dp[i][j]dp[i][j]=2||dp[i][j]
然后求 ans[] 数组, ans[sz]=dp[n][S]ans[sz]=sz ,然后 ans[]ans[sz]=szans[sz]=ans[sz]ans[sz+1]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <iostream>

#define MAXN 12
#define MAXM 120000
#define MOD 1000000007

using namespace std;

int n,m,k; //n*n大小的棋盘,m=2^(可以填颜色的格子个数),k=最大白色正方形边长不超过sz的情况下
char s[MAXN];
int a[MAXN]; //a[i]=第i行不能填颜色的格子状态
int ans[MAXN]; //ans[sz]=白色正方形边长最小为sz的方案数
int powsz[MAXN];
int dp[MAXN][MAXM]; //dp[i][j]=在第i行,状态为j的方案数
int flag[MAXN]; //flag[i]=1表示当前行中

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        m=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            //cout<<"m: "<<m<<endl;
            scanf("%s",s);
            for(int j=0;j<n;j++)
            {
                if(s[j]=='o')
                    m=m*2%MOD;
                else
                    a[i]|=1<<j;
            }
        }
        //cout<<"ddm: "<<m<<endl;
        ans[0]=1; //最小白色正方形边长为0,即全黑棋盘的方案数为1
        ans[1]=(m-1+MOD)%MOD; //最小白色正方形边长为1的方案数为2^(可以填颜色的格子个数)-1(相当于一个集合的所有子集个数)
        for(int sz=2;sz<=n;sz++) //求最小正方形为sz的方案数
        {
            powsz[0]=1; //powsz[i]=sz^i
            k=n+1-sz;
            for(int i=1;i<=k;i++)
                powsz[i]=powsz[i-1]*sz;
            dp[0][0]=1;
            for(int st=1;st<powsz[k];st++) //清零
                dp[0][st]=0;
            for(int i=1;i<=n;i++) //DP到第i行
            {
                for(int st=0;st<powsz[k];st++) //!!!!!清零
                    dp[i][st]=0;
                for(int cur=0;cur<(1<<n);cur++) //暴力枚举把集合cur中的格子都染成黑色
                {
                    if(cur&a[i]) continue; //有不能染色的格子在集合cur中,不合法
                    for(int j=0;j<k;j++)
                        flag[j]=0;
                    for(int bit=0;bit<n;bit++) //枚举该行的第bit列的格子
                    {
                        if(cur&(1<<bit)) continue; //这个格子是不能被染色的
                        for(int j=0;j<k;j++)
                            if(bit>=j&&bit<j+sz)
                                flag[j]=1;
                    }
                    for(int st=0;st<powsz[k];st++) //枚举第i行的状态st
                    {
                        if(!dp[i-1][st]) continue; //不合法的状态
                        int newst=0; //newst=由第i-1行推出的第i行的状态
                        for(int j=0;j<k;j++)
                        {
                            int t=st/powsz[j]%sz; //t是sz进制数st中的第j位数字
                            if(flag[j]) t=0;
                            else if(t!=sz-1) t++;
                            else
                            {
                                newst=-1;
                                break;
                            }
                            newst+=t*powsz[j];
                        }
                        if(newst==-1) continue; //由f[i-1][st]推出的f[i][st]为非法状态
                        dp[i][newst]=(dp[i][newst]+dp[i-1][st])%MOD;
                    }
                }
            }
            ans[sz]=0;
            for(int st=0;st<powsz[k];st++)
                ans[sz]=(ans[sz]+dp[n][st])%MOD;
            ans[sz]=(m-ans[sz]+MOD)%MOD; //求ans[sz]的补集后,此时ans[sz]=最小白色正方形边长大于等于sz的方案数
            ans[sz-1]=(ans[sz-1]-ans[sz]+MOD)%MOD;
        }
        for(int sz=0;sz<=n;sz++)
            printf("%d\n",ans[sz]);
    }
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[HDU 5079][2014 Asia AnShan Regional Contest]Square(DP套DP) 的相关文章

随机推荐

  • GBase 8a 问题处理-集群管理节点无法正常启动

    问题版本 GBase 8a V8 6 2 43 R20 问题简述 在进行迁移工作的数据导入之后 启动集群所有管理节点一直不能正常启动 通过命令service gcware stop 也不能停止 报错信息 gcadmin 报错 Could n
  • MySQL索引优化(超详细)

    Mysql索引优化 1 索引介绍 1 1 什么时MySQL的索引 MySQL官方对于索引的定义 索引是帮助MySQL高效获取数据的数据结构 MySQL在存储数据之外 数据库系统中还维护着满足特定查找算法的数据结构 这些数据结构以某种引用 指
  • CSDN竞赛-第六期

    CSDN编程竞赛报名地址 https edu csdn net contest detail 16 前言 背景 不知不觉 CSDN编程竞赛已经进行六期了 从我知道有这个竞赛的时候已经进行了两期 所以我是从第三期开始的 期间参与过三次 成绩在
  • 4,引擎初始化--(4)加载地图--2,创建world(学习资料来源于UE4游戏框架)

    加载地图时 创建完默认GameMode 就要创建world了 首先读取到package 创建world 从这里可以看到 地图是可以在初始化建立的 GameInstance是在运行起来后建立 两者是独立的 设为当前World 并设定为全局GW
  • leetcode:1905. 统计子岛屿

    题目来源 leetcode 1905 统计子岛屿 题目描述 class Solution public int countSubIslands vector
  • 漏洞情报

    点击上方 订阅话题 第一时间了解漏洞威胁 0x01 漏洞描述 WordPress ProfilePress 原 WP User Avatar 是一个轻量级会员插件 可用于创建用户画像 会员目录和用于用户注册 登录 密码重置及用户信息编辑的前
  • C++57个入门知识点_40 常成员函数(用于定义不可修改类内部成员变量的函数,一般用来修饰Get函数;常成员函数this指针:const T* const;常成员函数内部变量修改方法:强转/关键字)

    前面我们已经学习了C 中重要的知识点 特别是虚函数可能会有些懵逼 但是需要我们在实践中不断的理解和尝试 写代码是进步最快的方式 接下来将会介绍一些简单但很重要的知识点 本篇介绍常成员函数 总结 1 常成员函数 用于在程序中定义不可修改内部成
  • 关于红楼梦Python文本分析

    1 获取小说文本 读取文件 获取小说文本 读取文件 fn open prepare 红楼梦 曹雪芹 txt encoding utf 8 string data fn read 读出整个文件 fn close 关闭文件 2 对文本进行处理
  • oralce的判断语句

    大家对 IF ELSE 语句应该都很熟悉吧 它是用来对过程进行控制的 在 SQL 的世界中 CASE 语句有类似的效果 下面简单的介绍 CASE 语句的用法 CASE 语句的形式 事实上 CASE 语句有两种形式 1 SELECT 2 简单
  • 10. 微积分 - 微分&链式法则

    文章目录 微分 链式法则 Hi 大家好 我是茶桁 我们上节课讲了导数 并且在最后预告了今天的内容 今天将会是两部分 一部分是 微分 一部分是 链式法则 微分 微分 我们在导论里面提过 它和导数比较像 但是还是有差别的 实际的定义和内容都比较
  • 来吧!一文彻底搞定Vue组件!

    作者 Jeskson 来源 达达前端小酒馆 Vue组件的概述 组件是什么呢 了解组件对象的分析 Vue组件中的data属性 props传递数据的原理到底是什么 事件通信的那些事 如何了解父子组件事件通信 和遇到非父子组件事件通信如何处理 组
  • IP地址与用户行为

    IP地址能够解决网络风险和提高网络安全的原因是 所有的网络请求都会带有IP信息 是访问者的独立标识 另外ip地址的分配和管理比较严格 难以造假 另外ip属于网络层 可以轻松的对其进行阻断 现有的各种网络安全 负载均衡的设备和软件 都是以ip
  • 校园网上报修系统/宿舍报修系统的设计与实现

    摘要 随着科学技术的飞速发展 社会的方方面面 各行各业都在努力与现代的先进技术接轨 通过科技手段来提高自身的优势 校园网上报修系统当然也不能排除在外 从报修信息的统计和分析 在过程中会产生大量的 各种各样的数据 本文以校园网上报修系统为目标
  • 直流电路中升降压(Buck-Boost)变换电路的设计、参数选取及Matlab/Simulik仿真

    创作不易 感谢大家点赞关注支持 感兴趣的可以点击收藏 这一篇文章给大家介绍一种升降压 Buck Boost 直流变换电路 喜欢的可以点击收藏 升降压 Buck Boost 直流变换电路是通过调节开关管占空比的大小 占空比越小 输出电压越小
  • QT 之键盘事件(捕获键盘按下、松开事件)

    我们在做软件时候 经常会碰到这样的场景 比如按下F5进行刷新功能 按下F1进行帮助之类的快捷键方式 那么在QT中该怎样做呢 查阅文档 QT已经实现了这一系列的键盘事件 void QWidget keyPressEvent QKeyEvent
  • 拷贝构造和拷贝赋值

    拷贝构造表示有新的对象被定义 Object obj1 obj2 新的Object对象obj1被定义 此时调用拷贝构造函数 copy construction 拷贝赋值表示没有新的对象被定义 obj1 obj2 obj1是一个已经被声明过的对
  • WebSocket学习

    一 简介 WebSocket 是一种网络通信协议 RFC6455 定义了它的通信标准 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议 HTTP 协议是一种无状态的 无连接的 单向的应用层协议 它
  • Pythonの类

    Python是一种面向对象编程语言 因此类在Python中是很重要的概念 类是一种定义数据和行为的模板 可以创建对象并针对特定的问题对其进行操作 在Python中 类的定义以关键字 class 开头 后跟类的名称 类可以包含方法和属性 方法
  • mpvue实现微信小程序样式切换以及本地缓存

    功能描述 在页面A的添加应用中点击 添加 跳转到展示所有应用的页面B 通过点击开关 在页面A中展示所开启的应用 效果展示 代码 页面B代码 div class itembox div class boxhead img div class
  • [HDU 5079][2014 Asia AnShan Regional Contest]Square(DP套DP)

    题目链接 http acm hdu edu cn showproblem php pid 5079 题目大意 给你一个 n n n 8 n middot n n le 8 的棋盘 上面有一些格子必须是黑色 其它可以染黑或者染白 对于一个棋盘