codeforces D. Berland Fair+ set +dfs刪除
阿新 • • 發佈:2018-12-22
題目連結:http://codeforces.com/contest/1073/problem/D
題目大意:有n個圓形攤位,每個攤位出售一些糖果,價格為ai, 你有t元錢,你只能從1->n的方向買糖果,只要手中的錢大等於當前攤位出售糖果價格ai,就必須購買,一次只能買一個,問你最多能夠買多少個糖果。
第一圈: 5 2 5
剩餘: 38 33 31 26
第二圈 5 2 5
剩餘: 26 21 16 11
第三圈: 5 2 5
剩餘: 11 6 4(不能買)
第四圈: 5 2 5
剩餘: 4 (不能買) 4 2(不能買)
第五圈: 5 2 5
剩餘: 2 (不能買) 2 0(不能買)
u=3+3+2+1+1=10本書
因為:1≤n≤2*10^5
1≤T≤10^18
所以暴力模擬肯定會T,所以我們可以用 掃描+刪除 優化。
把所有的書存入set(以書的位置從小到大)
思路:
步驟1:如果當前的錢大於所有的書的價格和s,那麼u+=(t/s)*st.size();
步驟2:然後再從1->n掃一遍,如果當前的錢不能買此書,那麼以後一定不能再買,所以可以刪除此書(set的重點操作lgn的複雜度)。
set<R, rube>::iterator p_=ps;//記錄刪除的位置
ps++;//先++,防止刪除後再++,此時set已經沒有了ps指的位置,++找不到位置
s-=p_->s;//書的價格和減去刪除的書的價格
st.erase(p_);//刪除書
步驟3:如果t<書價格的最小值,break;否則繼續步驟1
邊掃描邊刪除,可以大幅度降低複雜度。
思考:set真是好用
#include<bits/stdc++.h> using namespace std; #define LL long long struct R { LL s; LL i; R(LL a, LL b){s=a, i=b;} R(){} }; struct rube { int operator()(const R& a, const R& b) { return a.i<b.i; } }; int cmp(R& a, R& b){return a.s>b.s;} set<R, rube> st; set<R, rube>::iterator ps; LL n; LL t=0, u=0, a, min_s=(1<<31)-1, s=0; LL dfs() { while(1) { if(t>=s)//擁有的錢大等於當前s所有書的價格和 { u+=(t/s)*st.size(); t%=s; } else { for(ps=st.begin();ps!=st.end();) { if(t>=ps->s)//擁有的錢大等於當前書的價格 { t-=ps->s; u++; ps++; } else //擁有的錢小於當前書的價格 { set<R, rube>::iterator p_=ps; ps++; s-=p_->s; st.erase(p_); } } } if(t<min_s) break; } } int main() { scanf("%lld%lld",&n,&t); for(int i=0;i<n;i++) { scanf("%lld",&a); s+=a, min_s=min(min_s, a); st.insert(R(a, i)); } dfs(); cout<<u<<endl; return 0; }