雅禮集訓 Day1 T1 養花

 

這道題的暴力很好寫。。

正解也很暴力。。。(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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章