题目描述
有一根长度为1000000000的棍子,一开始涂成白色。
棍子上有刻度,左端点为0,右端点1000000000。
由于某种原因这根棍子的某些部分被重新涂过了。
重新涂的颜色可能是黑色或着白色。
棍子总共被依次重新涂了N(1<=N<=5000)次。
找出最后最长的白色段。
Input
第1行一个数N。
接下来N行表示一次涂色,格式如下:
ai bi ci
ai和bi为整数,ci是字母b或w。
表示把ai和bi之间那段涂成ci色(w白色,b黑色)。
0<=ai<=bi<=1000000000。
Output
一行,两个数x和y(x如果有多个最长的段,输出x最小的一个。
分析
这题数据非常大,一看就知道不能只用暴力的。
虽然离散化一般用于压缩空间,但是事实上它是时空压缩的。
于是我们离散这个x和y到b里面,然后排序b。
接着按着开始输入的顺序在b里面查找x和y,将色涂在同样离散的数组f里。
差不多了。
#include <iostream>
#include <cstdio>
using namespace std;
long long n,a[5555][2],b[11111];
char c[5555];
bool f[11111];
long long i,j,k,be,en,x,y;
void qs(int l,int h)
{
long long i=l,j=h,mid=b[(l+h)/2],t;
if (l>h) return;
do
{
while (b[i]<mid) i++;
while (b[j]>mid) j--;
if (i<=j)
{
t=b[i];b[i]=b[j];b[j]=t;
i++;j--;
}
}
while (i<=j);
qs(l,j);
qs(i,h);
}
int main()
{
scanf("%lld",&n);
j++;
b[j]=0;
j++;
b[j]=1000000000;
a[1][0]=0;a[i][1]=1000000000;c[1]='w';
for (i=2;i<=n+1;i++)
{
scanf("%lld%lld",&a[i][0],&a[i][1]);
while (1)
{
scanf("%c",&c[i]);
if (c[i]=='w'||c[i]=='b') break;
}
j++;
b[j]=a[i][0];
j++;
b[j]=a[i][1];
}
qs(1,j);
for (i=1;i<=n+1;i++)
{
x=1;
while (b[x]!=a[i][0]) x++;
y=x+1;
while (b[y]!=a[i][1]) y++;
if (c[i]=='b')
{
for (k=x;k<=y-1;k++)
f[k]=1;
}
else
for (k=x;k<=y-1;k++)
f[k]=0;
}
i=0;
while (i<j)
{
i++;
if (!f[i])
{
x=b[i];
i++;
while (!f[i]&&i<j) i++;
y=b[i];
if (y-x>en-be)
{
be=x;
en=y;
}
}
}
printf("%lld %lld",be,en);
return 0;
}
针对长度为10亿的棍子,通过N次颜色覆盖操作,寻找最终最长连续白色段的有效算法实现。采用离散化处理和排序技巧,显著提高算法效率。
2007

被折叠的 条评论
为什么被折叠?



