zoukankan      html  css  js  c++  java
  • codeforces 727F. Polycarp's problems

    题目链接http://codeforces.com/contest/727/problem/F 
    题目大意:有n个问题,每个问题有一个价值ai,一开始的心情值为q,每当读到一个问题时,心情值将会加上该问题的价值。问题只能按顺序读。有m个询问,求当q=bi时,至少要删去多少个问题才能使得在任何时候心情值都>=0

    参考这篇:http://blog.csdn.net/aufeas/article/details/53031439

    解法一: 贪心

    分别求出最多删去i个问题需要的初始心情值的最小值f[i],最后在f数组上二分 求解答案。

    利用贪心暴力计算f[i], 即如果当前心情小于0,就去掉 价值最小的问题。 

    时间复杂度感人。。O(n^2*logn*log10^12+m*logn)

    我一开始用了set,一直TLE, 改成priority_queue就过了。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    #include <cstring>
    #include <set>
    using namespace std;
    
    #define N 800
    typedef long long ll;
    
    int n,m;
    int a[N];
    ll b[N];
    set<int> st;
    
    bool Check(ll lim,int k)
    {
        priority_queue<int,vector<int>,greater<int> > q;
        int cnt=0;
        for (int i=1;i<=n;i++)
        {
            if (a[i]>=0) lim+=a[i];
            else
            {
                q.push(a[i]); lim+=a[i];
                if (lim<0)
                {
                    lim-=q.top(); cnt++;
                    q.pop();
                    if (cnt>k) return false;
                }
            }
        }
        return true;
    }
    
    ll Calc(int k)
    {
        ll L=0,R=1e12,Mid;
        while (L<R)
        {
            Mid=(L+R)>>1;
            if (Check(Mid,k)) R=Mid;
            else L=Mid+1;
        }
        return L;
    }
    
    int Solve(ll lim)
    {
        int L=0,R=n,Mid;
        while (L<R)
        {
            Mid=(L+R)>>1;
            if (b[Mid]<=lim) R=Mid;
            else L=Mid+1;
        }
        return L;
    }
    
    int main()
    {
        //freopen("in.in","r",stdin);
        //freopen("out.out","w",stdout);
        
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        
        for (int i=0;i<=n;i++) b[i]=Calc(i);
        
        ll lim;
        for (int i=1;i<=m;i++) 
        {
            scanf("%I64d",&lim);
            printf("%d
    ",Solve(lim));
        }
        
        return 0;
    }
    View Code

    解法二: DP

    这个dp有点巧妙,是从后往前的顺序。

    dp[i][j]表示考虑i-n这些问题,最多只能去掉j个问题, 初始心情至少要多少。   如果求出dp数组,最后只要在dp[1]上二分求答案就好了。

    如果a[i]>=0, 那么a[i]这个问题肯定没必要删掉, dp[i][j]=dp[i+1][j]-a[i];

    如果a[i]<0 , dp[i][j]=min(dp[i+1][j]-a[i] ,  dp[i+1][j-1]);  分别是删掉a[i]和不删的情况。

    如果算出来dp[i][j]<0, 那么dp[i][j]=0.    因为要保证中间过程不会心情有负的情况。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    #include <cstring>
    #include <set>
    using namespace std;
    
    #define N 800
    typedef long long ll;
    
    int n,m;
    int a[N];
    ll dp[N][N];
    
    int Solve(ll lim)
    {
        int L=0,R=n,Mid;
        while (L<R)
        {
            Mid=(L+R)>>1;
            if (dp[1][Mid]<=lim) R=Mid;
            else L=Mid+1;
        }
        return L;
    }
    
    int main()
    {
        //freopen("in.in","r",stdin);
        //freopen("out.out","w",stdout);
        
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        
        for (int i=n;i>=1;i--)
        {
            for (int j=0;j<=n-i+1;j++)
            {
                if (a[i]<0) 
                {
                    if (j) dp[i][j]=min(dp[i+1][j]-a[i],dp[i+1][j-1]);
                    else dp[i][j]=dp[i+1][j]-a[i];
                }
                else dp[i][j]=dp[i+1][j]-a[i];
                if (dp[i][j]<0) dp[i][j]=0;
                
            }
        }
    
        ll lim;
        for (int i=1;i<=m;i++) 
        {
            scanf("%I64d",&lim);
            printf("%d
    ",Solve(lim));
        }
        
        return 0;
    }
    View Code

     

  • 相关阅读:
    asp.net获取当前页面的url地址
    取多个name值相同的input里面的值
    多线程实践
    《谷物大脑》是骗子写的伪科学书:樊登著作4本,都是3星
    历史远未终结,全球化面临挑战:4星|《世界不是平的》
    大众汽车的恐吓文化导致了排放门:4星|《像职场赢家一样做减法》
    穿越回秦朝能发电吗?能:4星|《1分钟物理》
    作者没有实战经验,案例老旧,图表水平差:2星|《社群思维》
    滴滴优步面临各地竞争对手难以通吃:4星|《哈佛商业评论》第3期
    2星|《重新定义物流》:形式像PPT,内容像公关稿
  • 原文地址:https://www.cnblogs.com/vb4896/p/6099424.html
Copyright © 2011-2022 走看看