Description
M将军在战神等人的帮助上踏上了大山,成立了一个王国,取名为大山中学集训队。王国中文有规律帝,武有战神,下面还有一群哥字辈,牛字辈的小兵和闪闪发光的明日之星,渐渐地,这些人都成了富翁,退出了王国政坛。为了重组新的一批政坛成员,将军决定举行一场科举考试。
将军亲自请了离开已久的萌训和萌浩出山,来当这次科举考试的出题者。由于退役已久,两个想了很久,最后萌训出了一道这样的题:给定N个数和T个询问,每个询问为给定一个区间,求下标在这个区间内的数的最大值;萌浩则出了的一道这样的题:给定一个a、p,求a除以p的余数。
将军觉得两道题太难,商量之后合成一道这样的题:给定N个数和T个询问,每个询问为给定一个区间,求下标落在这个区间内的数除以p之后的余数最大值。现在你就是考生,解决它吧。
Solution
这题关键是 \(a_i\le 1000\),对此我们可以开 1000 个桶,记录每个数字出现的位置。
对于询问,可以从大到小枚举答案 \(b\),然后再枚举 \(a\),判断 \(ap+b\) 这个数出现的位置中是否有在 \([l,r]\) 中的点,可以通过二分解决。
如果时间超限,可以将常数优化一下。
Code
#include<cstdio>
#include<vector>
#include<algorithm>
#define MX 1005
using namespace std;
vector<int> t[MX];
int n,m,l,r,p,mx,ans;
int read()
{
int res=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
return res;
}
bool check(int x,int p,int q)
{
vector<int>::iterator k=lower_bound(t[x].begin(),t[x].end(),p);
if (k!=t[x].end()&&*k<=q) return true;
else return false;
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;++i)
{
int x=read();
t[x].push_back(i);
mx=max(mx,x);
}
while (m--)
{
l=read()+1;r=read()+1;p=read();
ans=0;
for (int i=p-1;i>=0;--i)
{
for (int j=0;j*p+i<=mx;++j)
{
if (!t[j*p+i].size()) continue;
if (check(j*p+i,l,r))
{
ans=i;
break;
}
}
if (ans) break;
}
printf("%d\n",ans);
}
return 0;
}