2018 雅礼集训 DAY1T1 养花

考试拿两年前的雅礼集训题考,自闭了。

mdnmd,这就全都不会做呗。

desprition

C 在家种了 \(n\) 盆花, 每盆花有一个艳丽度 \(a_i\). 在接下来的 m 天中, 每天早晨他会从一段编号连续的花中选择一盆摆放在客厅, 并在晚上放回 同时每天有特定的光

照强度 \(k_i\), 如果这一天里摆放在客厅的花艳丽度为 \(x\) , 则他能获得的喜悦度为 \(x \bmod k_i\). 他希望知道, 每一天他能获得的最大喜悦度是多少.

Input Format

数据第一行包含两个正整数 \(n\), $ m$ . 接下来一行 \(n\) 个正整数, 第 \(i\) 个数 \(a_i\) 表示第 \(i\) 盆花的艳丽度.

接下来 \(m\) 行, 每行三个正整数 \(l_i\) \(r_i\) $ k_i$, 表示选花区间和光照强度

Output Format

输出 m 行, 每行一个整数, 表示最大喜悦度

Constraints

对于 20% 的数据, \(n, m ≤ 4000\).

对于 40% 的数据, \(n, m ≤ 50000\).

对于另外 20% 的数据, \(a_i ≤ 300\).

对于 100% 的数据, \(n, m, a_i , k_i ≤ 10^5\)

sloution

讲个笑话,正解是分块。

我们可以考虑预处理出对于每个模数,每个块的答案。

这个预处理大概可以做到 \(O(n + k\ln k)\)

我们要求的是 形如 \([ak,(a+1)k-1]\) 这一段区间的最大值 减去 \(ak\) 的结果。

那么我们就可以枚举每个 \(ak\) ,然后算出在这个答案。

直接暴力枚举的话,复杂度还是比较高,所以求一下前缀最大值就可以。

询问的复杂度是 \(O(ms)\) 的,取 \(s = \sqrt{k\ln k}\) 是达到最优复杂度 \(n \sqrt{k\ln k}\)

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
const int N = 1e5+10;
int n,m,block,l,r,w;
int sum[1001][N],tong[N],a[N];
using namespace std;
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void YYCH()
{
	for(int i = 1; i <= (n-1)/block+1; i++)
	{
		memset(tong,0,sizeof(tong));
		for(int j = (i-1) * block + 1; j <= min(i * block, n); j++) tong[a[j]] = a[j];
		for(int j = 1; j <= 100000; j++) tong[j] = max(tong[j],tong[j-1]);//求前缀最大值
		for(int j = 1; j <= 100000; j++)//枚举每个模数
		{
			for(int k = 0; k <= 100000; k += j)//枚举每个 ak
			{
				sum[i][j] = max(sum[i][j],tong[min(k+j-1,100000)]-k);//ak - (a+1)k-1 的最大值
			}
		} 
	}
}
int query(int l,int r,int w)//正常的分块询问
{
	int ans = 0;
	int fx = (l-1) / block + 1, fy = (r-1) / block + 1;
	for(int i = l; i <= min(fx * block, r); i++) ans = max(ans,a[i] % w);
	for(int i = fx+1; i <= fy-1; i++) ans = max(ans,sum[i][w]);
	for(int i = max((fy-1) * block + 1,l); i <= r; i++) ans = max(ans,a[i] % w);
	return ans;
}
int main()
{
	freopen("flower.in","r",stdin);
	freopen("flower.out","w",stdout);
	n = read(); m = read(); block = 1000;
	for(int i = 1; i <= n; i++) a[i] = read();
	YYCH();
	for(int i = 1; i <= m; i++)
	{
		l = read(); r = read(); w = read();
		printf("%d\n",query(l,r,w));
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

posted @ 2020-10-26 07:38  genshy  阅读(172)  评论(0编辑  收藏  举报