2018.09.17 atcoder Tak and Hotels(贪心+分块)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82750960

传送门
一道有意思的题。
一开始想错了,以为一直 l o w e r lower _ b o u n d bound 就可以解决询问,结果交上去TLE了之后才发现时间复杂度是错的。
但是贪心思想一定是对的,每次向前尽量推进一定可以得到最优解。
于是我想起了一道叫做弹飞绵羊的题,感觉这道题可以类比。
码了一会一直WA感觉不太对,发现有一个细节写错了233。
A了之后在csdn上翻了翻题解。
发现都是倍增优化%%%,我被自己的低智商给蠢哭了,是啊连修改操作都没有分块很low啊。
不过还是讲讲如何分块吧。
对于一个数i,我们保存它弹到下一个与它不是同一个块的点所需的最小步数以及那个点的下标。
这样大块直接跳,小块就循环。
代码:

#include<bits/stdc++.h>
#define N 100005
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int l,n,x[N],Q,tim[N],nxt[N],hd,tl,q[N],blo[N],sig;
int main(){
	n=read(),sig=sqrt(n);
	for(int i=1;i<=n;++i)x[i]=read();
	l=read(),Q=read();
	hd=tl=1,q[tl]=n,tim[n]=0,nxt[n]=n+1,blo[n+1]=blo[n]+1;
	for(int i=n-1;i;--i){
		while(x[q[hd]]-x[i]>l)++hd;
		nxt[i]=q[hd],q[++tl]=i;
	}
	for(int i=1;i<=n;++i)blo[i]=(i-1)/sig+1;
	for(int i=n-1;i;--i)
		if(blo[nxt[i]]==blo[i])tim[i]=nxt[i]==n?1:tim[nxt[i]]+1,nxt[i]=nxt[nxt[i]];
		else tim[i]=1;
	while(Q--){
		int a=read(),b=read(),cnt=0;
		if(a>b)a^=b,b^=a,a^=b;
		while(blo[a]<blo[b])cnt+=tim[a],a=nxt[a];
		int sum=0;
		for(int i=a+1;i<=b;++i){
			if(sum+x[i]-x[i-1]>l)sum=0,++cnt;
			sum+=x[i]-x[i-1];
		}
		if(sum)++cnt;
		printf("%d\n",cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82750960
今日推荐