雅礼集训 Day1 T1 养花

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/83211201

 

这道题的暴力很好写。。

正解也很暴力。。。(PS:吐槽数据。。说好的≤100000却出现了100001)

正解分块。

主要思路是处理出每个块对于每个模数的最大余数。乍一看好想只能n^{2}(那我优化什么???)

其实可以nlnn。。因为可以处理出块内到每个数为止的最大值。之后枚举每个数作为模数,再枚举起始点,

起始点+模数-1,也就是加上最大余数,在这个范围内的最大的数%模数就是要求的最大模数。。

这样的时间就是\sum_{i=1}^{n} \ \frac{n}{i}也就是n*\sum_{i=1}^{n} \ \frac{1}{i}而后面就是调和级数,时间是lnn,这样最终的时间就是块数S*nlnn

那么为了时间,我们去共\sqrt{nlnn}块,这样总时间就是\frac{n}{\sqrt{nlnn}}*nlnn= n*\sqrt{nlnn},就不会超时了。

nlnn的最大情况就是1e5*(11.512925464970228420089957273422)差不多为10,那么分1000块比较好。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 100000
using namespace std;
int n,m,l,r,k;;
int val[100005];
int f[100005];
int blg=1000;
int mx[105][100005];
int main()
{
	freopen("flower.in","r",stdin);
	freopen("flower.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&val[i]);
	}
	int num=(n-1)/blg+1;
	for(int i=1;i<=num;i++)
	{
		memset(f,0,sizeof(f));
		int l=(i-1)*blg+1,r=min(i*blg,n);
		for(int j=l;j<=r;j++)f[val[j]]=val[j];
		for(int j=1;j<=N;j++)f[j]=max(f[j],f[j-1]);
		for(int j=1;j<=N;j++)
		{
			for(int k=0;k<=N;k+=j)
			{
				mx[i][j]=max(mx[i][j],f[min(k+j-1,N)]-k);
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		int l,r,k;
		scanf("%d%d%d",&l,&r,&k);
		int l1=(l-1)/blg+1,r1=(r-1)/blg+1;
		int ans=0;
		for(int j=l1+1;j<=r1-1;j++)
		{
			ans=max(ans,mx[j][k]);
		}
		for(int j=l;j<=min(l1*blg,r);j++)
		{
			ans=max(ans,val[j]%k);
		}
		for(int j=max((r1-1)*blg+1,l);j<=r;j++)
		{
			ans=max(ans,val[j]%k);
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zzk_233/article/details/83211201
今日推荐