zoukankan      html  css  js  c++  java
  • poj 3266 Cow School 分数规划

    这个题目难度非常大,首先对于老师的一种方案,应用分数规划的一般做法,求出所有的c=t-rate*p,如果没有选择的c值中的最大值比选择了的c值中的最小值大,那么这个解是可以改进的。

    那么问题就转化成了怎么求最小的c和最大的c。

    t-rate*p 求这种类型的最值,并且rate是单调的,那么就可以考虑利用斜率优化的那种办法来维护决策点。

    考虑两个决策点,得到ti-tj>rate(pi-pj)  但是这个pi pj的大小不能确定,我们知道可以利用斜率优化的问题不仅仅要rate单调,还需要pi 单调 这个时候我们需要利用题目中的条件,题目中保证了t/p单调,根据这个条件,可以推出求两种最值的时候都只有单调的p才是有可能成为决策点的。那么就可以按照斜率优化步骤来解题了。一个是用单调栈维护,另外一个利用单调队列维护。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=5e4+9;
    double high[maxn],low[maxn];
    long long sumt[maxn],sump[maxn];
    struct D
    {
        long long t,p;
        bool operator <(const D & xx) const
        {
            return t*xx.p>xx.t*p;
        }
    }test[maxn];
    int que[maxn];
    
    bool chk(int i,int j,int t,int s)
    {
        long long a=(test[i].t-test[j].t)*(test[t].p-test[s].p);
        long long b=(test[t].t-test[s].t)*(test[i].p-test[j].p);
        return a>b;
    }
    
    bool chk2(int i,int j,long long t,long long p)
    {
        long long a=(test[i].t-test[j].t)*p;
        long long b=t*(test[i].p-test[j].p);
        return a>b;
    }
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++)
            scanf("%lld %lld",&test[i].t,&test[i].p);
            sort(test+1,test+1+n);
    
            for(int i=1;i<=n;i++)
            {
                sumt[i]=sumt[i-1]+test[i].t;
                sump[i]=sump[i-1]+test[i].p;
            }
    
            int front=1,end=0;
            for(int i=1;i<=n;i++)
            {
                while(end>=front&&test[i].p>=test[que[end]].p)
                end--;
                while(end>front&&chk(que[end],i,que[end-1],que[end]))
                end--;
                que[++end]=i;
                while(front<end&&chk2(que[front],que[front+1],sumt[i],sump[i])==1)
                front++;
                int u=que[front];
                low[i]=test[u].t-(double)sumt[i]/sump[i]*test[u].p;
            }
            int top=0;
            for(int i=n;i>=1;i--)
            {
                while(top>0&&test[i].p<=test[que[top]].p)
                top--;
                while(top>1&&chk(i,que[top],que[top],que[top-1]))
                top--;
                que[++top]=i;
                while(top>1&&chk2(que[top],que[top-1],sumt[i-1],sump[i-1])==0)
                top--;
                int u=que[top];
                high[i]=test[u].t-(double)sumt[i-1]/sump[i-1]*test[u].p;
            }
            int ans=0;
            for(int i=1;i<n;i++)
            if(high[i+1]>low[i])
            ans++;
            cout<<ans<<endl;
            for(int i=n-1;i>=1;i--)
            if(high[i+1]>low[i])
            printf("%d
    ",n-i);
        }
        return 0;
    }
    


     

  • 相关阅读:
    commons-dbutils实现增删改查(spring新注解)
    commons-dbutils实现增删改查
    配置扫描注解的包
    常用注解
    注入集合类型数据
    spring创建bean的三种方式
    switch
    jvm编译器的优化
    java9小工具jshell
    java三元运算符
  • 原文地址:https://www.cnblogs.com/pangblog/p/3315434.html
Copyright © 2011-2022 走看看