1. 程式人生 > >codeforces D. Berland Fair+ set +dfs刪除

codeforces D. Berland Fair+ set +dfs刪除

題目連結: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;
}