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. JVM有哪些垃圾回收器

    JVM 的垃圾回收器 目录 JVM 的垃圾回收器 经典垃圾收集器 Serial 收集器 ParNew 收集器 Parallel Scavenge 收集器 Serial Old 收集器 Parallel ...

  2. 【Azure 应用服务】App Service中,为Java应用配置自定义错误页面,禁用DELETE, PUT方法

    问题定义 使用Azure应用服务(App Service),部署Java应用,使用Tomcat容器,如何自定义错误页面呢?同时禁用DELETE, PUT方法 解决办法 如何自定义错误页面呢?需要在 J ...

  3. canvas性能-drawImage渲染图片

    canvas性能-绘制图片 目录 canvas性能-绘制图片 canvas绘制图片 drawImage putImageData createPattern 测试绘制耗时 drawImage Imag ...

  4. 05. struts2中为Action属性注入值

    概述 struts2为Action中的属性提供了依赖注入功能 在struts2的配置文件中,我们可以很方便地为Action中的属性注入值.注意:属性必须提供get,set方法. 配置 <acti ...

  5. 浅谈java中线程和操作系统线程

    在聊线程之前,我们先了解一下操作系统线程的发展历程,在最初的时候,操作系统没有进程线程一说,执行程序都是串行方式执行,就像一个队列一样,先执行完排在前面的,再去执行后面的程序,这样的话很多程序的响应就 ...

  6. 一文搞定全场景K3s离线安装

    作者简介 王海龙,Rancher中国社区技术经理,负责Rancher中国技术社区的维护和运营.拥有6年的云计算领域经验,经历了OpenStack到Kubernetes的技术变革,无论底层操作系统Lin ...

  7. "INVALID" is not a valid start token

    Search · is not a valid start token https://github.com/prometheus/prometheus/search?q=is+not+a+valid ...

  8. WPF排版布局经验总结(干货)简短不疲倦

    本文不过多讲述wpf的基础布局控件,本文只记录WPF排版的技巧,这是个人的总结,不能符合所有情况,如果有何不对的地方,请评论指正,谢谢. 1.区域划分 在接手一个界面的时候,先纵观全局,将眼见的区域划 ...

  9. 90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(1)- JIT编译优化

    麻烦大家帮我投一票哈,谢谢 经常听到 Java 性能不如 C/C++ 的言论,也经常听说 Java 程序需要预热,那么其中主要原因是啥呢? 面试的时候谈到 JVM,也有很多面试官喜欢问,为啥 Java ...

  10. java 文件转成pdf文件 预览

    一.前端代码 //预览功能 preview: function () { //判断选中状态 var ids =""; var num = 0; $(".checkbox& ...