5177: [Jsoi2013]贪心的导游 暴力+主席树

Description
南京有一条著名的购物街。购物街嘛,就是一排整齐的商店啦~
导游小Z每次都会把游客团带到购物街里走一段,然后选择一个商店进去购物。小Z接待的游客都是购物狂,他们恨不得将店内的商品洗劫一空,也就是说,只要他们能买,就一定会继续买(钱够不够你不用考虑,他们都有信用卡可以透支)。但是有一点,他们都非常讲究平等、很谦虚,每个人都不能忍受比别人多买什么东西或者少买什么东西,于是他们每个人最后买的商品数量都是一样的。这虽然导致他们没办法每次都把商店搬空,但是每次已经给店家带来一大笔生意了,店家已经非常感谢了!为了表示感谢,店家决定把游客们买完之后剩下来那几件没卖掉的商品就送给导游小Z了。贪心的小Z自然希望自己能获赠的商品数量越大越好啦~现在告诉你这一排共n个商店(标号为0到n-1)每个商店里的商品总数,每次小Z会带一批共p个游客的旅游团,到其中u号商店和v号商店之间逛一逛,请你帮小Z在所逛的商店区间内选择一个,告诉小Z他最多能获赠多少件商品。

题解:

数据真的很水啊!我的暴力枚举p的倍数都过了啊,然后加个主席树找一下区间内小于某数的最大数就过了啊!想更快的话我是想对于小的p可以建线段树来搞。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=2000010;
const int Maxm=50010;
const int inf=2147483647;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,a[Maxn];
int lc[Maxn*11],rc[Maxn*11],c[Maxn*11],root[Maxn],cnt=0;
void insert(int &u,int l,int r,int p)
{
    if(!u)u=++cnt;c[u]++;
    if(l==r)return;
    int mid=l+r>>1;
    if(p<=mid)insert(lc[u],l,mid,p);
    else insert(rc[u],mid+1,r,p);
}
void merge(int &u1,int u2)
{
    if(!u1){u1=u2;return;}
    if(!u2)return;
    c[u1]+=c[u2];
    merge(lc[u1],lc[u2]);
    merge(rc[u1],rc[u2]);
}
int query(int r1,int r2,int l,int r,int k)
{
    if(c[r1]>=c[r2])return 0;
    if(l==r)return l;
    int mid=l+r>>1;
    int re=0;
    if(k>mid&&c[rc[r1]]!=c[rc[r2]])re=query(rc[r1],rc[r2],mid+1,r,k);
    if(re)return re;
    return query(lc[r1],lc[r2],l,mid,k);
}
int main()
{
    n=read(),m=read();int mx=0;
    for(int i=1;i<=n;i++)a[i]=read(),mx=max(mx,a[i]);
    for(int i=1;i<=n;i++)insert(root[i],0,2000,a[i]),merge(root[i],root[i-1]);
    while(m--)
    {
        int l=read()+1,r=read()+1,p=read(),ans=0;
        for(int i=p-1;;i+=p)
        {
            int t=query(root[l-1],root[r],0,2000,i);
            ans=max(ans,t%p);
            if(i>=mx)break;
        }printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值