title: woj1012 Thingk and Count DP好题

date: 2020-03-12

categories: acm

tags: [acm,dp,woj]

难题,dp好题,几何题(?数学题)

想明白了其实思路很简单,但是因为数据量很大优化需要考虑.

滚动数组。

description

You are given a chessboard made up of N squares by M squares. Some of the squares are colored black, and the others are colored white. Please

write a program to calculate the number of rectangles which are completely made up of white squares.

输入格式

There are multiple test cases. Each test case begins with two integer N,M (1 <= N , M<= 2000), the board size. The following N lines, each with M

characters, have only two valid character values:

b - representing a black square;

w - representing a white square.

Process to the end of file.

输出格式

For each test case in the input, output the number of white rectangles a line.

样例输入

2 3

bbb

www

2 2

bw

wb

样例输出

6

2

analyse

dp经典。

f(i,j)为以点[i][j]为右下角的矩形数量,这里化为滚动数组sum。

经验教训:

这种看着像dp 的可以试一试dp,然后找递推公式的时候注意,新增的i,和原来整体对比看有什么关系或者和i-1有什么关系

几何体画图,多画几种情况,考虑全

数据量很大的时候,用滚动数组

然后这种方块题通解就是计算以[i,j]为底的矩形数累加

然后考虑数据量用long long,输出%lld

hud1510//zoj2067

ZJU的1985也可以看一看

code final

//zoj2067改woj1012,再改良版
//zoj2067改woj1012见下面的注释
#include <cstdio>
#include <cstring>
#include<iostream>
using namespace std;
int n,m; const int maxn=2005; char g[maxn];
int f[maxn]; //当前行x,i列上[x,i]为底的矩形高度
long long ans; //ans很大,考虑溢出
int pre[maxn];
long long sum[maxn]; //sum[i]记录以[x,i]为右下角的所有矩形数量,这样[x,i+1]如果f[i+1]>f[i]直接查表就行
/*pre[i]为最近的比i列矩形低的矩形的距离 比如
a a
a a a a pre[2]=1,pre[3]=1.pre[i]=0表示i列是0-i中最矮列,比如pre[0]=0;
*/
int main(int argc, char *argv[])
{
while( scanf("%d %d",&n,&m)!=EOF ){
getchar(); //注意,没有可不可以?
ans=0;
for(int i=0;i<m;i++)
f[i]=0;
for(int i=0; i<n; i++){ //按行建图并在建立完一行后就计算以该行上的方块为右下角的矩形数量
scanf("%s",g);
for(int j=0;j<m;j++)
if(g[j]=='b')
f[j]=0;
else
f[j]++;
sum[0] = 0 ;
pre[0]=0; //初始时没有比0列更矮(或相等)的列,距离为0
for(int j=0;j<m;j++){
if(j==0)
sum[j]+=f[j];
else if(f[j]>=f[j-1]){
sum[j]=f[j]+sum[j-1];
pre[j]=1;
}
else if(f[j]<f[j-1]){
pre[j]=pre[j-1]+1;
int temp=j-pre[j];
while(f[temp]>f[j]&&pre[temp]){ //当templie比j列高并且temp列是0-temp最矮列的时候,就没必要继续找了
temp=temp-pre[temp];
} //考虑比j列矮的列就可以,不必考虑最矮列,比如高度为 1232342(0-6列),sum[6]=sum[3]+f[6]*(6-3),因为3之前的就算有更矮的,也已经被sum[3]计算时考虑过了
if(f[temp]>f[j]) //找不到比j列矮的列
{
pre[j]=0;
sum[j]=f[j]*(j+1);
}
else{ //找到比j列矮的列temp
pre[j]=j-temp;
sum[j]=f[j]*(j-temp)+sum[temp];
}
}
//cout<<j<<" "<<sum[j]<<"// "; 调试的时候用
ans+=sum[j];
}
//cout<<endl;
}
printf("%d\n",ans); //这里ans考虑完了,一开始用的还是%d,一直WA,所以注意啊
}
return 0;
}

code α

zoj2067改编到woj1012,超时。如果这个代码里改成m=n,判断改成=='#',zoj2067可AC

状态:f(i,j)为记录i行j列,[i][j]为底的符合要求的正方形连续组成的矩形的高度

以[i][j]为右下角的矩形初值为f(i,j)

然后在i行从j-1 到 0 遍历矩形高度,不为0就可以扩展成以[i][j]为右下角的矩形

计算每个以每个点为右下角的矩形数量求和即为解

比如

a a

a a a a

a a a b ,算以b为右下角的矩形的时候先算了第三列,ans+3,然后前一列高度为3=3,ans+3,然后ans+2,ans+2...

然后看到网上很多的滚动数组版,节省了时间(节省时间不是滚动数组,是滚动数组的意义和计算方法),感觉不太清楚,就按照一个思路写了上面的代码

//zoj2067 ac
//结果还是在woj1012 te了。
#include <cstdio>
#include <cstring>
#include<iostream>
using namespace std;
int n,m; const int maxn=2005; char g[maxn][maxn];
int f[maxn][maxn];
int ans,tmp; int main(int argc, char *argv[])
{
while( scanf("%d %d",&n,&m)!=EOF ){
getchar();
ans=0;
for(int i=0; i<n; i++){ //建图
scanf("%s",g[i]);
for(int j=0;j<m;j++){
if(g[i][j]=='b') //这里也可以优化。只用一个数组表示f[i][j]就行,因为一旦该点为0就和上面没关系了,而不为0直接++就行
f[i][j]=0;
else{
if(i==0)
f[i][j]=1;
else
f[i][j]=f[i-1][j]+1;
ans+=f[i][j];
tmp=f[i][j];
for(int k=j-1;k>=0;k--){ //然后这里可以优化,记录比前一个自己所在矩形高度低的列就行,没必要每一列都循环
if(f[i][k]==0)
break;
else{
if(tmp>f[i][k])
tmp=f[i][k];
ans+=tmp;
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
网上比较多的AC代码,思路和最上面我的代码一样,但是我觉得p,pre不太容易理解
#include<iostream>
#include<cstdio> using namespace std; int main(){
char in[2001];
long sign[2001], i, min, sum[2001], pre[2001], j, k, n, m, s, p;
long long out;
while (scanf("%ld %ld\n", &n, &m) != EOF)
{
for (i = 1; i <= m; i++) //每一列当前连续白色方块数为0
sign[i] = 0;
for (s = 1, out = 0; s <= n; s++)
{
scanf("%s",in); //因为按行处理,保留一行就可以 gets(in)也可以,和%s一样略过了最后的\n
for (i = 0; i < m; i++)//记录i列s行,[s][i]为底的符合要求的正方形连续组成的矩形的高度,滚动数组1,处理单列上的白方块总数
{
if (in[i] == 'w') //注意这里是sign[i+1],为了下面的处理方便
sign[i + 1]++;
else
sign[i + 1] = 0;
} //然后横向处理计算以[s][i]为右下角的矩形的数量
for (i = 1, sign[0] = pre[0] = 0; i <= m; i++) //0列是虚构的一列。注意输入是从in[0]开始的,为了方便处理i从1开始
{
if (sign[i] >= sign[i - 1])//如果比前列的矩形高,以[s][i-1]为右下角的所有的矩形都可以扩展到以[s][i]为右下角的矩形,同时i列以[s][i]为右下角的矩形数量为sign[i]
{
sum[i] = sum[i - 1] + sign[i];//滚动数组2,记录前i列的白方块总数
pre[i] = 0; //pre[i] 比i列矩形高度低的列的距离-1
}
else
{
pre[i] = pre[i - 1] + 1;
p = i - pre[i];
while (p > 0 && sign[p - 1] >= sign[i])//找出比这列sign[]小的列
p = p - pre[p - 1] - 1;
if (p <= 0)//这列sign[]值最小,h*w计算[s][i]为右下角的矩形就可以
{
sum[i] = sign[i] * i;
pre[i] = 0;
} else//p列sign[]值最小,分两部分,p列前的可以扩展到[s][i]为右下角的矩形,而p列到i列可以按h*w算
{
sum[i] = sign[i] * (i - p + 1) + sum[p - 1];
pre[i] = i - p - 1;
}
}
out += sum[i]; //每列加一次,加新生成的矩形数
}
}
printf("%lld\n", out);
}
return 0; }

woj1012 Thingk and Count DP好题的更多相关文章

  1. 【dp入门题】【跟着14练dp吧...囧】

    A HDU_2048 数塔 dp入门题——数塔问题:求路径的最大和: 状态方程: dp[i][j] = max(dp[i+1][j], dp[i+1][j+1])+a[i][j];dp[n][j] = ...

  2. dp杂题(根据个人进度选更)

    ----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目; dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推 ...

  3. DP百题练(一)

    目录 DP百题练(一) 线性 DP 简述 Arithmetic Progressions [ZJOI2006]物流运输 LG1095 守望者的逃离 LG1103 书本整理 CH5102 移动服务 LG ...

  4. DP百题练(二)

    目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...

  5. ACM :漫漫上学路 -DP -水题

    CSU 1772 漫漫上学路 Time Limit: 1000MS   Memory Limit: 131072KB   64bit IO Format: %lld & %llu Submit ...

  6. [poj2247] Humble Numbers (DP水题)

    DP 水题 Description A number whose only prime factors are 2,3,5 or 7 is called a humble number. The se ...

  7. poj 3254 状压dp入门题

    1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...

  8. POJ 1155 TELE 背包型树形DP 经典题

    由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...

  9. 13年山东省赛 The number of steps(概率dp水题)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud The number of steps Time Limit: 1 Sec  Me ...

随机推荐

  1. dblink查找对应的目标端session

    v$session试图中process字段代表的是客户端所在机器的进程号 例如我使用toad连接数据库,查询到的process即toad的进程号 SELECT process FROM V$SESSI ...

  2. Ice系列--强大如我IceGrid

    前言 IceGrid是一个提供服务定位和服务激活的组件,但它的功能远不止于此.从它的命名可以看出它的设计理念-网格计算(grid computing).网格计算被定义为由一系列关联的廉价计算机组成的计 ...

  3. floating point

    记录浮点数的单精度和双精度(IEEE754) 1.单精度(float) ​ 1.定义:单精度占4字节/32位,其中1号位符号位,其次是8位阶码/指数(阶符+阶数),23位尾数(小数). 2.双精度(d ...

  4. 订阅者模式,公众号、B站、快手用了都说好!

    大家好,今天和大家来聊一个新的设计模式--订阅者模式. 这个模式在我们的生活当中非常常见,可以说是几乎所有的媒体平台都用或多或少地用到了这个模式.比如公众号,我们来仔细梳理一下公众号这个平台当中的整个 ...

  5. 8.3 Customizing Git - Git Hooks 钩子 自动拉取 自动部署 提交工作流钩子,电子邮件工作流钩子和其他钩子

    https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks https://github.com/git/git/blob/master/temp ...

  6. 【实战】ZooKeeper 实战

    1. 前言 这篇文章简单给演示一下 ZooKeeper 常见命令的使用以及 ZooKeeper Java客户端 Curator 的基本使用.介绍到的内容都是最基本的操作,能满足日常工作的基本需要. 如 ...

  7. LOJ10199轻拍牛头

    题目描述 原题来自:USACO 2008 Dec. Silver 今天是 Bessie 的生日,并且现在是聚会的游戏时间.Bessie 让编号为 1~N 的 N 头奶牛围成一个圈坐(所以除了最后一头牛 ...

  8. koa2+koa-generator+mysql快速搭建nodejs服务器

    koa2+koa-generator+mysql快速搭建nodejs服务器 用koa的脚手架koa-generator可以快速生成项目骨架,可以用于发开或者测试接口 https://github.co ...

  9. Redis,JedisPool工具类

    Redis,JedisPool工具类 1.JedisPool 详细配置解释代码 2.Jedis工具类 导入相关依赖: commons-pool2-2.3.jar jedis-2.7.0.jar 1.J ...

  10. Spark使用Java、Scala 读取mysql、json、csv数据以及写入操作

    Spark使用Java读取mysql数据和保存数据到mysql 一.pom.xml 二.spark代码 2.1 Java方式 2.2 Scala方式 三.写入数据到mysql中 四.DataFrame ...