A: 怎样更有力气
时间限制: 2 Sec 内存限制: 128 MB提交: 96 解决: 12
[ 提交][ 状态][ 讨论版]
题目描述
OI大师抖儿在夺得银牌之后,顺利保送pku。这一天,抖儿问长者:“我虽然已经保送了,但我的志向是为国家健康工作五十年。请问我应该
怎样变得更有力气?
”
长者回答:“你啊,Too Young Too Simple,Sometimes Naive! 如果你想要我教你,你要先进行艰苦的修行。 ”
长者回答:“你啊,Too Young Too Simple,Sometimes Naive! 如果你想要我教你,你要先进行艰苦的修行。 ”
长者的住宅中有一堵长度为n的墙
。
每天抖儿起床修行,会
选择
一段长度为x的区间染成白色。长者的住宅附近有一群香港记者,为了借助抖儿拜访长者,
第i
天香港记者会将
区间
[
l
i
,
r
i
]
染成白色来讨好抖儿
(也就是说,每天墙会被抖儿和香港记者各染一次)。
现在抖儿已经预先知道了香港记者的动向,他想知道他最少几天就能把墙全部染白,完成修行。
输入
第一行三个整数n,m,x,分别表示墙的长度,天数和区间的长度。
接下来m行,每行两个整数
l
i
、r
i
,表示香港记者在第i天会将区间
[
l
i
,
r
i
]
染成白色。
输出
一行一个整数,表示抖儿最少几天能把墙全部染白。
如果m天之后依然无法染白,则输出“Poor Douer!”
样例输入
10 3 32 54 89 10
样例输出
2
提示
【样例说明】
第一天抖儿刷墙的区间为[1,3]
第二天抖儿刷墙的区间为[8,10]
【限制与约定】
测试点编号
|
n
|
m
|
x
|
1
|
n≤10
|
m≤1
|
|
2
|
n≤10
|
m≤10
|
|
3
|
n≤100
|
m≤100
|
|
4
|
n≤1000
|
m≤1000
|
|
5
|
n≤10000
|
m≤10000
|
|
6
|
n≤100000
|
m≤100000
|
x=0
|
7
|
n≤10
18
|
||
8
|
n≤100000
|
||
9
|
n≤10
18
|
||
10
|
对于所有的数据,保证
n≤10
18
,m≤100000,x≤n且数据随机
【后记】
在你的帮助下,抖儿完成修行的时间是原来的0.01倍。
抖儿对长者说:“我明白了!只有每天坚持锻炼,才能获得力量。”
长者嘿嘿一笑:“你想多了。我只是想让你刷墙而已。”
说完,长者一溜烟地跑了,速度比香港记者还要快
好几倍
。
1、当m=1时比较简单。
2、n,m≤10^4
考虑第i天,先处理香港记者染白的区间。
令dp[i]表示1~i全染白至少操作几次。
则dp[i]=dp[i-1](i为白点)或dp[i-x]+1(i为黑点)
时间复杂度O(nm)
3、x=0
二分答案,那么只要看香港记者染白的区间是否将墙完全覆盖即可。
将区间按左端点排序,比较区间的左端点与前一个区间的右端点即可。
4、正解
其实已经很明了了。
在3中,如果当前区间的左端点小于上一个区间的右端点,就直接退出。
现在只要从上一个区间的右端点+1开始凃,一直涂到≥当前区间左端点即可。
注意到一次可能直接把整一段覆盖了,那么下一次就要从当前涂到的地方开始。
Code:
var
l1,r1,l,r:array[1..100000] of int64;
m,i,tt:longint;n,x:int64;
procedure sort(a,b:longint);
var i,j,x,y,p:longint;
begin
i:=a;j:=b;
x:=l1[(a+b) div 2];p:=r1[(a+b) div 2];
repeat
while (l1[i]<x)or((l1[i]=x)and(r1[i]<p)) do inc(i);
while (l1[j]>x)or((l1[j]=x)and(r1[j]>p)) do dec(j);
if not(i>j) then
begin
y:=l1[i];l1[i]:=l1[j];l1[j]:=y;
y:=r1[i];r1[i]:=r1[j];r1[j]:=y;
inc(i);dec(j);
end;
until i>j;
if a<j then sort(a,j);
if i<b then sort(i,b);
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
function right(k:longint):boolean;
var i,tt:longint;ans:int64;
begin
for i:=1 to k do
begin
l1[i]:=l[i];
r1[i]:=r[i];
end;
sort(1,k);
ans:=0;
if (x=0)and(l1[1]>1) then exit(false) else
begin
if l1[1]>1 then
begin
if ((l1[1]-1) mod x=0) then ans:=ans+(l1[1]-1) div x else
ans:=ans+(l1[1]-1) div x+1;
r1[1]:=max(x,r1[1]);
end;
for i:=2 to k do
begin
if l1[i]<=r1[i-1]+1 then
begin
r1[i]:=max(r1[i],r1[i-1]);
continue;
end;
if (x=0) then exit(false) else
begin
if ((l1[i]-r1[i-1]-1) mod x=0) then
tt:=((l1[i]-r1[i-1]-1) div x) else
tt:=(l1[i]-r1[i-1]-1) div x+1;
ans:=ans+tt;
r1[i]:=max(r1[i-1]+x*tt,r1[i]);
r1[i]:=max(r1[i],r1[i-1])
end;
if ans>k then exit(false);
end;
if r1[k]<n then
begin
if x=0 then exit(false);
if (n-r1[k]) mod x=0 then
ans:=ans+(n-r1[k]) div x else
ans:=ans+(n-r1[k]) div x+1;
end;
end;
if ans>k then exit(false) else exit(true);
end;
function find(a,b:longint):longint;
var mid:longint;
begin
if a=b then exit(a);
mid:=(a+b) div 2;
if right(mid) then
find:=find(a,mid) else find:=find(mid+1,b);
end;
begin
readln(n,m,x);
for i:=1 to m do readln(l[i],r[i]);
if not(right(m)) then writeln('Poor Douer!') else
writeln(find(1,m));
end.