CodeForces 521D Shop

題面

題意

給出n個數,有m種操作,操作分爲三類:
1.將第i個數改成某個數
2.將第i個數加上某個數
3.將第i個數乘上某個數
每種操作只能做一次,從中選擇至多k個,求操作後的數的乘積的最大值。

做法

貪心,首先操作順序肯定是:修改(可以看作加,且至多一次),加,乘。
難點在於要加多少個數在開始乘,正確處理方式是將加轉化爲乘,a+b就相當於a*(a+b/a),而加法的順序是確定的(從大到小),所以可以將所有加法轉化爲乘一個分數,然後將分數排序即可。
最後注意要根據操作排序。
因爲加法轉化爲分數可能會爆long long,建議將分數-1來存儲。

代碼

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
#define ll long long
#define P pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
#define N 100100
using namespace std;

ll n,m,k,num[N],cz[N];
P chg[N];
inline ll gcd(ll u,ll v)
{
    for(;u&&v&&u!=v;)
    {
        swap(u,v);
        u%=v;
    }
    return max(u,v);
}
struct Fs
{
    ll fz,fm,id;
    void yf()
    {
        ll g=gcd(fz,fm);
        fz/=g;
        fm/=g;
    }
    bool operator < (const Fs &u) const
    {
        return fz*u.fm<fm*u.fz;
    }
}tmp;
vector<P>add[N];
vector<ll>ans;
priority_queue<Fs>pq;

inline bool cmp(P u,P v){return u>v;}
inline bool cmp2(ll u,ll v){return cz[u]<cz[v];}

int main()
{
    ll i,j,o,p,q;
    cin>>n>>m>>k;
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&num[i]);
    }
    for(i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&o,&p,&q);
        cz[i]=o;
        if(o==1)
        {
            chg[p]=max(chg[p],mp(q-num[p],i));
        }
        else if(o==2)
        {
            add[p].push_back(mp(q,i));
        }
        else
        {
            tmp.fz=q-1;
            tmp.fm=1;
            tmp.id=i;
            pq.push(tmp);
        }
    }
    for(i=1;i<=n;i++)
    {
        if(chg[i].fi) add[i].push_back(chg[i]);
        sort(add[i].begin(),add[i].end(),cmp);
        o=num[i];
        for(j=0;j<add[i].size();j++)
        {
            tmp.fz=add[i][j].fi;
            tmp.fm=o;
            tmp.id=add[i][j].se;
            tmp.yf();
            pq.push(tmp);
            o+=add[i][j].fi;
        }
    }
    for(i=1;i<=k&&!pq.empty();i++)
    {
        ans.push_back(pq.top().id);
        pq.pop();
    }
    cout<<ans.size()<<endl;
    sort(ans.begin(),ans.end(),cmp2);
    for(i=0;i<ans.size();i++) printf("%lld ",ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章