czl SRM 15
众所周知,czl家养了一只可♂爱的***(已屏蔽),那只东西很贪吃,所以czl家很多零食仓库,然而这些仓库里有很多老鼠。
为了心爱的***,czl决定点燃纯艾条,用烟熏老鼠。
共有N个仓库,编号1-N。
假设陵陵在第i个仓库点燃艾条,烟雾就会充满该仓库,并向左右扩散Ai 的距离,接着所有|i-j|<=Ai 的仓库 j 的老鼠被消灭。
陵陵是个爱护环境的人,他想知道最少需要多少支艾条,才可以消灭所有老鼠。
【输入格式】
第一行:一个正整数,代表 N。
第二行:N 个非负整数,第 i 个数代表 A i 。
【输出格式】
第一行:一个整数,代表答案。
【样例】
Inout:
5
2 3 3 3 3
Output:
1
【数据范围】
20%的数据:N <= 20
60%的数据:N <= 10^3
100%的数据:N <= 5*10^5 ,Ai<=N
然而我根本没看出是线段覆盖
一直往dp的方向上想。。
我感觉以后做题还是要把模型抽象出来(具体说来,就是要画图!!)
然而知道了是线段覆盖了之后还是不知道要怎么做
去复习了一下codevs的线段覆盖1~5
在这里简答总结一下。
--------------------------分割线---------------------------------------------------------------------
(那里的线段覆盖是不要重叠)
最基本的就是dp
f[i]表示从1到i的最多线段数(强制i要选)
从i前面的j递推过来。
if(没有重叠)f[i]=max(f[j])+1
最后在f[i]里面取个max就可以了
这样是n^2的
之后就是贪心
对于当前能选择的线段,优先选择右端点最大的(刚好和本题相反)
接下里就是带上价值的线段了
n^2dp的做法与上相同
但我们发现更大的数据只能接受nlogn的复杂度
这时我们就想到二分出从哪里转移过来
而要支持二分必须具有单调性
右端点经过排序,是具有单调性的
所以我们要使dp值也具有单调性
这时我们可以把f[i]换成不强制i一定选
这样就可以f[i]=max(f[j]+vi[i],f[i-1])
这样f就具有单调性了(不下降)
我们就可以二分转移了
--------------------------分割线---------------------------------------------------------------------
至于本题
就是刚刚讲的贪心做法啦
注意点不是实数点,而是整数点
所以判断线段之间没有缝隙是l<=r+1而不是l<=r
然后就没什么了
还是太菜啊。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int N=5*1e5+20;
struct node
{
int l,r;
}e[N];
bool cmp(node a,node b)
{
return a.l<b.l;
}
int main()
{
int n,k;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&k),e[i].l=std::max(1,i-k),e[i].r=std::min(n,i+k);
std::sort(e+1,e+1+n,cmp);
int last=1;
int i=1;int ans=0;
while(last<n)
{
int max=0;
while(i<=n&&e[i].l<=last+1) max=max>e[i].r?max:e[i].r,i++;
last=max;
ans++;
}
printf("%d\n",ans);
return 0;
}