• 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

     

  • 相关阅读:
    springMVC的@RequestMapping的参数和用法
    springMVC的helloword
    eclipse 导入MyEclipse创建的web项目该如何启动?
    解决mysql中文乱码
    java核心技术 卷1 基础知识—对象与继承
    Java核心技术 卷1 基础知识—概述、环境
    python爬虫框架之scrapy的快速上手
    如何评测软件工程知识技能水平
    金融文本挖掘的业务领域建模
    金融文本挖掘中的针对业务的用例建模
  • 原文地址:https://www.cnblogs.com/vb4896/p/6099424.html
Copyright © 2020-2023  润新知