Loading

3283. 【GDOI2013】大山王国的科举考试

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;
}
posted @ 2022-02-26 16:45  Thunder_S  阅读(107)  评论(0编辑  收藏  举报