• CF727F [Polycarp's problems] & [EX_Polycarp's problems]


    原题题意

    给出长度为n的有序数组,m次询问,每次给出一个正整数x。你要删除数组中最少的元素,使得数组中的前缀和+x都为非负整数。允许离线,n≤750,m≤200,000。


    原题思路

    首先注意到,x能成功通过测试当且仅当前缀和中最小的数≥x。

    将询问从大到小排个序,对于一个新的询问,每次尝试从数组中删除最优的一个数,使得成功的机会更大。

    何为最优?我们注意到,ai只会对后面的数造成影响。设当前前缀和最小为now,fi为前i个前缀和中最小的数,则答案会增加 max { min { now-ai , fi-1 } } (请注意后面的f囊括了now-ai顾及不到的情况)。

    每次判断最小的数在哪,暴力更新,O(n3+mlogm)。


    代码

     1 #pragma GCC optimize(2)
     2 #include<bits/stdc++.h> 
     3 using namespace std;
     4 typedef long long int ll;
     5 const ll inf=1000000000000000000;
     6 const ll maxn=1E6+5;
     7 template<typename T> void read(T &x){
     8     x=0;char ch=getchar();int fh=1;
     9     while (ch<'0'||ch>'9'){if (ch=='-')fh=-1;ch=getchar();}
    10     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    11     x=x*fh;
    12 }
    13 void write(ll x)
    14 {
    15     if(x==0){putchar('0');putchar('\n');return;}
    16     if(x<0){putchar('-');x=-x;}
    17     ll a[25],size=0;
    18     while(x){a[++size]=x%10;x/=10;}
    19     for(int i=size;i>=1;--i)putchar(a[i]+'0');
    20     putchar('\n');
    21 }
    22 ll min(ll x,ll y){return x<y?x:y;}
    23 ll max(ll x,ll y){return x>y?x:y;}
    24 ll n,m,a[maxn],tot,sum[maxn],ans[maxn],f[maxn];
    25 struct query{ll pos,x;}Q[maxn];
    26 bool cmp(query a,query b){return a.x>b.x;}
    27 ll get()
    28 {
    29     ll ans=inf;
    30     for(int i=1;i<=n;++i)
    31     {
    32         sum[i]=sum[i-1]+a[i];
    33         ans=min(ans,sum[i]);
    34         f[i]=min(f[i-1],sum[i]);
    35     }
    36     return ans;
    37 }
    38 int main()
    39 {
    40     read(n);read(m);
    41     for(int i=1;i<=n;++i)
    42     {
    43         read(a[i]);
    44         if(a[i]<0)++tot;
    45     }
    46     for(int i=1;i<=m;++i)
    47     {
    48         read(Q[i].x);
    49         Q[i].pos=i;
    50     }
    51     sort(Q+1,Q+m+1,cmp);
    52     int pos=1;
    53     for(int i=1;i<=tot;++i)
    54     {
    55         ll g=get();
    56         while(Q[pos].x+g>=0&&pos<=m){ans[Q[pos].pos]=i-1;++pos;}
    57         if(g>=0)break;
    58         ll ans=-inf,pos=0;
    59         for(int j=1;j<=n;++j)
    60         {
    61             if(min(g-a[j],f[j-1])>ans)
    62             {
    63                 ans=min(g-a[j],f[j-1]);
    64                 pos=j;
    65             }
    66         }
    67         a[pos]=0;
    68     }
    69     ll g=get();
    70     while(Q[pos].x+g>=0&&pos<=m){ans[Q[pos].pos]=tot;++pos;}
    71     for(int i=1;i<=m;++i)write(ans[i]);
    72     return 0;
    73 }
    View Code

     

     

     

    EX版本:

    m,n≤1,000,000,强制在线。


    思路

    考虑从后往前贪心。我们先只考虑两种情况(0显然没必要考虑)。

    第一种,所有的数均为负数。则每次答案必然会从最小的数删起,直到删的数的绝对值第一次大于等于询问。

    第二种,只有一个数为正,其余均为负。两种情况:

           第一种,加起来为仍为正,那么就不会删数。并且这一位不会对以后造成任何影响(既然都加上正数了,能到达这一位,以后肯定不会小于零)。

      第二种,加起来为负。那么会贪心地选择最小的负数删,直到加起来为正。换个角度,会贪心地选择最大的负数加到正数上,直到正数为负。这样,化归为第一情况。

           再将负数加入大根堆,正数不要的原因同第一种。

    图画画,手算算至少能够理解。

    最后得到的答案要么剩下正数,要么全是负数。这些负数取反后,从大到小排序的第i位代表了取到第i种答案,要删去1~i个数。

    二分查找即可。


    代码

     1 #pragma GCC optimize(2)
     2 #include<bits/stdc++.h> 
     3 using namespace std;
     4 typedef long long int ll;
     5 const ll inf=1000000000000000000;
     6 const ll maxn=1E6+5;
     7 ll min(ll x,ll y){return x<y?x:y;}
     8 ll max(ll x,ll y){return x>y?x:y;}
     9 template<typename T> void read(T &x){
    10     x=0;char ch=getchar();int fh=1;
    11     while (ch<'0'||ch>'9'){if (ch=='-')fh=-1;ch=getchar();}
    12     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    13     x=x*fh;
    14 }
    15 void write(ll x)
    16 {
    17     if(x==0){putchar('0');putchar('\n');return;}
    18     if(x<0){putchar('-');x=-x;}
    19     ll a[25],size=0;
    20     while(x){a[++size]=x%10;x/=10;}
    21     for(int i=size;i>=1;--i)putchar(a[i]+'0');
    22     putchar('\n');
    23 }
    24 ll n,m,a[maxn],wait[maxn],size,x;
    25 priority_queue<ll>Q;
    26 int main()
    27 {
    28     read(n);read(m);
    29     for(int i=1;i<=n;++i)read(a[i]);
    30     for(int i=n;i>=1;--i)
    31     {
    32         while(a[i]>=0&&!Q.empty())
    33         {
    34             a[i]+=Q.top();
    35             Q.pop();
    36         }
    37         if(a[i]<0)Q.push(a[i]);
    38     }
    39     while(!Q.empty())
    40     {
    41         wait[++size]=Q.top();
    42         Q.pop();
    43     }
    44     for(int i=1;i<=size/2;++i)swap(wait[i],wait[size-i+1]);
    45     for(int i=1;i<=size;++i)wait[i]+=wait[i-1];
    46     for(int i=1;i<=size;++i)wait[i]=-wait[i];
    47     while(m--)
    48     {
    49         read(x);
    50         write(lower_bound(wait,wait+size+1,wait[size]-x)-wait);
    51     }
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    头文件#ifndef #define #endif使用
    Django框架【form组件】
    数据库【mysql】之pymysql
    数据库【mysql篇】典型的一些练习题目
    Python开发【socket篇】解决粘包
    Python开发【内置模块篇】os模块
    Python开发【内置模块篇】日志模块
    Python开发【内置模块篇】configparser
    Python开发【内置模块篇】collections
    Python开发【内置模块篇】datetime
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/10603543.html
Copyright © 2020-2023  润新知