#树状数组、dp#JZOJ 5361 捕老鼠

题目

农夫约的农庄里有\(N\)个仓库,排成了一排,编号为\(1~N\)
假设猫在第\(i\)个仓库点燃艾条,烟雾就会充满该仓库,并向左右扩散\(Ai\)的距离,接着所有\(|i-j|<=Ai\) 的仓库\(j\) 的老鼠被消灭。
猫是一只爱护空气环境的好猫,它希望知道最少需要多少支艾条,才可以消灭所有老鼠。


分析

考虑处理出每个右端点能同时扩散的最小的左端点,
那么状态转移方程显然,用数据结构维护


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=500011; int c[N],f[N],dp[N],n;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed fan(int x){return n-x+1;}
inline signed query(int x){
	rr int ans=f[0];
	for (;x;x-=-x&x)
	    ans=min(ans,c[x]);
	return ans;
}
inline void update(int x,int y){
	for (;x<=n;x+=-x&x) c[x]=min(c[x],y);
}
signed main(){
	freopen("cat.in","r",stdin);
	freopen("cat.out","w",stdout); 
	n=iut()+1,memset(f,0x3f,sizeof(f));
	for (rr int i=1;i<n;++i){
		rr int x=iut(),R=min(i+x,n-1);
		f[R]=min(f[R],(i<=x)?1:(i-x));
	}
	memset(c,0x3f,sizeof(c)),update(fan(1),dp[1]=0);
	for (rr int i=1;i<n;++i) if (f[i]<=i)
	    update(fan(i+1),dp[i+1]=query(fan(f[i]))+1);
	return !printf("%d",dp[n]);
} 
posted @ 2020-11-02 21:29  lemondinosaur  阅读(68)  评论(0编辑  收藏  举报