• CF436F Banners


    Description

    All modern mobile applications are divided into free and paid. Even a single application developers often release two versions: a paid version without ads and a free version with ads.

    Suppose that a paid version of the app costs $ p $ ( $ p $ is an integer) rubles, and the free version of the application contains $ c $ ad banners. Each user can be described by two integers: $ a_{i} $ — the number of rubles this user is willing to pay for the paid version of the application, and $ b_{i} $ — the number of banners he is willing to tolerate in the free version.

    The behavior of each member shall be considered strictly deterministic:

    - if for user $ i $ , value $ b_{i} $ is at least $ c $ , then he uses the free version,
    - otherwise, if value $ a_{i} $ is at least $ p $ , then he buys the paid version without advertising,
    - otherwise the user simply does not use the application.

    Each user of the free version brings the profit of $ c×w $ rubles. Each user of the paid version brings the profit of $ p $ rubles.

    Your task is to help the application developers to select the optimal parameters $ p $ and $ c $ . Namely, knowing all the characteristics of users, for each value of $ c $ from $ 0 $ to $ (max b_{i})+1 $ you need to determine the maximum profit from the application and the corresponding parameter $ p $ .

    Solution

    发现$p$的最优值肯定是某个用户的$a$

    先将所有用户按照$b$排序,那么枚举$c$时就可以单调地将每个用户加入一个数据结构,广告费可以$O(1)$计算,现在只需要考虑软件付费

    设$d_i$表示$p$值为$i$时产生的总收益,那么加入一个用户时会对所有$i < a$的$d$增加一个$i$,相当于区间加等差数列

    可以在值域上分块,对于完整的块更改标记,不完整的块暴力重建

    每次查询的时候对每个块中的最大值求$max$即可

    现在考虑如何找到每个块中的最大值

    设标记为$cnt$,那么当$i < j$且$d_i+i imes cnt < d_j +j imes cnt$,有

    $$frac{d_i - d_j}{j-i} leq cnt$$

    那么在每个块内用队列维护一个下凸壳即可

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,w,B,blo[100005],q[320][320],h[320],t[320],pos=1,cnt[320],maxa;
    long long d[100005];
    struct Node{
        int a,b;
        bool operator < (const Node &z)const{return b<z.b;}
    }node[100005];
    inline int read(){
        int w=0,f=1;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return w*f;
    }
    double slope(int x,int y){return 1.0*(d[x]-d[y])/(y-x);}
    void solve(int x){while(h[x]<t[x]&&slope(q[x][h[x]],q[x][h[x]+1])<=cnt[x])++h[x];}
    void insert(int x){
        if(!x)return;
        for(int i=1;i<blo[x];i++)++cnt[i],solve(i);
        int l=(blo[x]-1)*B+1,r=min(blo[x]*B,maxa),id=blo[x];
        for(int i=l;i<=r;i++)d[i]+=1ll*cnt[id]*i;
        for(int i=l;i<=x;i++)d[i]+=i;
        h[id]=1,t[id]=0;
        for(int i=l;i<=r;i++){
            while(h[id]<t[id]&&slope(q[id][t[id]-1],q[id][t[id]])>=slope(q[id][t[id]],i))--t[id];;
            q[id][++t[id]]=i;
        }
        cnt[id]=0,solve(id);
    }
    int main(){
        n=read(),w=read();
        for(int i=1;i<=n;i++)node[i]=(Node){read(),read()},maxa=max(maxa,node[i].a);
        sort(node+1,node+n+1),B=sqrt(maxa);
        for(int i=1;i<=maxa;i++)blo[i]=(i-1)/B+1;
        for(int i=1;i<=blo[maxa];i++)h[i]=t[i]=1,q[i][1]=min(maxa,i*B);
        for(int c=0;c<=node[n].b+1;c++){
            while(pos<=n&&node[pos].b<c)insert(node[pos].a),++pos;
            long long ans1=0,ans2=0;
            for(int i=1;i<=blo[maxa];i++){
                int x=q[i][h[i]];
                if(1ll*cnt[i]*x+d[x]>ans1)ans1=1ll*cnt[i]*x+d[x],ans2=x;
            }
            printf("%I64d %I64d
    ",ans1+1ll*w*c*(n-pos+1),ans2);
        }
        return 0;
    }
    Banners
  • 相关阅读:
    删除表数据drop、truncate和delete的用法
    List,DataTable实现行转列的通用方案
    C#正则表达式简单限制输入11位手机号
    Oracle数据库byte存放汉字,9个汉字x3=27个字节
    SQL 语句
    $("p").fadeOut("fast")设置淡出效果
    神奇的 toLocaleString
    C#中精确计时的一点收获
    Web service stop after running serveral hours
    SQL Server中like匹配下划线的方法
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14259118.html
Copyright © 2020-2023  润新知