安徽师大附中%你赛day9 T3 贵 解题报告

问题描述

苟先生的狼狗大军没有追上富先生, 所以他把它们都解雇了, 决定去雇佣一些更好的狗, 不过狗可是很贵的。苟先生有 \(w\) 元钱, 有 \(n\) 条狗可以雇佣, 第 \(i\) 条狗有一个能力值 \(q_i\)和一个需求 \(s_i\), 也就是说给它的钱不能少于 \(s_i\)。 对于两条狗 \(i\)\(j\),给它们的钱的比值必须等于 \(q_i/q_j\)(当然钱可以不为整数) 。 苟先生希望雇佣到尽量多的狗, 并花尽量少的钱。

输入格式

第一行两个整数 \(n\)\(w\)
接下来 \(n\) 行每行两个整数 \(s_i\)\(q_i\)

输出格式

第一行一个整数 \(m\) 表示雇佣的数量, 接下来 \(m\) 行每行一个整数表
示雇佣的编号, 可以任意输出一组合法的解。

数据范围与约定

对于 50%的数据 \(n<=5000\)
对于 100%的数据 \(n<=100000,w<=10^{10},s_i,q_i<=20000\)


首先吐糟数据,100%的数据只有50分,事实上是5e5

因为判最小钱判错了,而且掉到可持久化坑里,坚定的认为这个题可持久化才能输出方案,所以只有10pts

从一堆奇奇怪怪的东西里找到正解可以说是很不容易了,旁边的ouuanjulao几秒就出正解了

\(\frac{s_i}{q_i}\)从小到大排序,我们发现如果以最低价选了某个位置\(i\)的东西,那么它左边的选择都可以唯一确定了,总花费是\(s_i \times \frac{\sum_{j=1}^i p_j}{p_i}\)

贪心的选,我们先选\(p\)小的就行了

可以用堆维护统计。。我没想到用的平衡树。。

保证钱最小 不等于 保证\(\sum_{j=1}^i p_j\)最小...


Code:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <ctime>
#define ls ch[now][0]
#define rs ch[now][1]
using namespace std;
const int N=5e5+10;
int n;
double w;
struct node
{
    double s,q;
    int num;
    bool friend operator <(node n1,node n2)
    {
        return n1.s/n1.q<n2.s/n2.q;
    }
}dog[N];
double dat[N],sum[N];
int ch[N][2],siz[N],num[N],val[N],tot,root;
void updata(int now)
{
    siz[now]=siz[ls]+siz[rs]+1;
    sum[now]=sum[ls]+sum[rs]+dat[now];
}
void split(int now,double k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(k>=dat[now])
        x=now,split(rs,k,rs,y);
    else
        y=now,split(ls,k,x,ls);
    updata(now);
}
void split1(int now,double k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(k>=sum[ls]+dat[now])
        x=now,split1(rs,k-sum[ls]-dat[now],rs,y);
    else
        y=now,split1(ls,k,x,ls);
    updata(now);
}
int Merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(val[x]<val[y])
    {
        ch[x][1]=Merge(ch[x][1],y);
        updata(x);
        return x;
    }
    else
    {
        ch[y][0]=Merge(x,ch[y][0]);
        updata(y);
        return y;
    }
}
int New(double k,int id)
{
    num[++tot]=id,sum[tot]=dat[tot]=k,siz[tot]=1,val[tot]=rand();
    return tot;
}
void Insert(double k,int id)
{
    int x,y;
    split(root,k,x,y);
    root=Merge(x,Merge(New(k,id),y));
}
int cnt,cnt0,ans[N],Ans;double cost;
void dfs(int now)
{
    ans[++cnt0]=num[now];
    if(ls) dfs(ls);
    if(rs) dfs(rs);
}
void query(double q,double s,int id)
{
    int x,y;
    double k=w*q/s;
    split1(root,k,x,y);
    if(cnt<siz[x])
    {
        cost=sum[x]*s/q;
        cnt=siz[x];
        Ans=id;
        //dfs(x);
    }
    if(cnt==siz[x]&&sum[x]*s/q<cost)
    {
        cost=sum[x]*s/q;
        Ans=id;
        //dfs(x);
    }
    root=Merge(x,y);
}
int main()
{
    srand(time(0));
    freopen("gui.in","r",stdin);
    freopen("gui.out","w",stdout);
    scanf("%d%lf",&n,&w);
    cost=w;
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&dog[i].s,&dog[i].q);
        dog[i].num=i;
    }
    sort(dog+1,dog+1+n);
    for(int i=1;i<=n;i++)
    {
        Insert(dog[i].q,dog[i].num);
        query(dog[i].q,dog[i].s,i);
    }
    memset(ch,0,sizeof(ch));
    root=tot=0;
    for(int i=1;i<=Ans;i++)
        Insert(dog[i].q,dog[i].num);
    int x,y;
    split1(root,w*dog[Ans].q/dog[Ans].s,x,y);
    dfs(x);
    printf("%d\n",cnt);
    sort(ans+1,ans+1+cnt);
    for(int i=1;i<=cnt;i++)
        printf("%d\n",ans[i]);
    return 0;
}


2018.8.21

posted @ 2018-08-21 17:06  露迭月  阅读(154)  评论(0编辑  收藏  举报