1. 程式人生 > >5177: [Jsoi2013]貪心的導遊 暴力+主席樹

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); } }