1113: [Poi2008]海报PLA
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 751 Solved: 453
[ Submit][ Status]
Description
N个矩形,排成一排. 现在希望用尽量少的矩形海报Cover住它们.
Input
第一行给出数字N,代表有N个矩形.N在[1,250000] 下面N行,每行给出矩形的长与宽.其值在[1,1000000000]2 1/2 Postering
Output
最少数量的海报数.
Sample Input
5
1 2
1 3
2 2
2 5
1 4
![](http://www.lydsy.com/JudgeOnline/images/1113_1.jpg)
1 2
1 3
2 2
2 5
1 4
![](http://www.lydsy.com/JudgeOnline/images/1113_1.jpg)
Sample Output
4
![](http://www.lydsy.com/JudgeOnline/images/1113_2.jpg)
RMQ/单调栈。
如果两个矩形能同时被一个海报覆盖,要满足两个条件:
1.他俩的高度相同
2.他们之间的海报没有比他俩更矮的
先说我的做法:
用RMQ预处理出区间最小值,然后依次枚举即可。
但要注意一个问题,如果有好多个矩形高度相同,那么需要从每一个为起点,来进行判断,可行则跳出,不可行则继续枚举。
好麻烦。。
其实正解是单调栈。。
维护一个单调递增的栈(因为如果当前高度比之前小,那么之前的永远不可能满足要求了);
如果遇到和队尾相同的,那么使答案减1。
下面是我的RMQ代码(无视掉Solve()。。那是我的对拍)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define M 250005
using namespace std;
int f[M][20],h[M],n;
struct data
{
int x,p;
}a[M];
void read(int &tmp)
{
tmp=0;
char ch=getchar();
int fu=1;
for (;ch<'0'||ch>'9';ch=getchar())
if (ch=='-') fu=-1;
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=tmp*10+ch-'0';
tmp*=fu;
}
void RMQ()
{
for (int i=1;i<=n;i++)
f[i][0]=h[i];
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+(1<<j)-1<=n;i++)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int Getlog(int x)
{
int now=1;
for (int i=0;;i++)
{
now<<=1;
if (now>=x) return i;
}
}
int Getmin(int l,int r)
{
int k=Getlog(r-l+1);
return min(f[l][k],f[r-(1<<k)+1][k]);
}
int Solve(int l,int r)
{
if (l==r) return 1;
int ans=1;
int m=Getmin(l,r);
int cnt=0;
for (int i=l;i<=r;i++)
if (h[i]==m) cnt++;
if (cnt==1) return r-l+1;
int from=l;
for (int i=l;i<=r;i++)
if (h[i]==m)
{
if (from<i) ans+=Solve(from,i-1);
from=i+1;
}
if (from<=r) ans+=Solve(from,r);
return ans;
}
bool cmp(data a,data b)
{
if (a.x==b.x) return a.p<b.p;
return a.x<b.x;
}
int main()
{
read(n);
int x;
for (int i=1;i<=n;i++)
read(x),read(h[i]),a[i].x=h[i],a[i].p=i;
RMQ();
sort(a+1,a+1+n,cmp);
int now=1;
int ans=n;
while (now<=n)
{
int r=now;
while (r+1<=n&&a[r+1].x==a[r].x)
r++;
int k=now+1;
for (int i=now;i<r;i++)
{
if (k<=i) k=i+1;
int j;
for (j=k;j<=r;j++)
{
if (Getmin(a[i].p,a[j].p)==a[i].x) ans--;
else {k=j;break;}
}
if (j>r) break;
}
now=r+1;
}
cout<<ans<<endl;
return 0;
}
hzwer的单调栈代码。
#include<iostream>
#include<cstdio>
using namespace std;
int t,x,n,s[250001],top,ans;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&t,&x);
while(x<=s[top])
{
if(x==s[top])ans++;
top--;
}
s[++top]=x;
}
printf("%d",n-ans);
return 0;
}
感悟:
单调栈写起来有简单速度又快。。关键是抓住两者之间不能有比他们矮的这个条件。