codeforces568 div2:Exam in BerSU (hard version)、Extra Element

C2、Exam in BerSU (hard version)

:给定n,m.n个学生,给出第i个学生通过测验需要的时间。n个学生按编号顺序依次考试。总的测试时间超过m则考试结束,剩下的人视为考试失败。问对第1个到第n个学生,要使第i个学生通过考试,则至少要几个人考试不通过(考试不通过则耗时为0)注意每个学生的结果相互独立。

M (1≤n≤2⋅10^5,1≤n≤2⋅10^5) , ti (1≤ti≤100) 

solution:首先想到贪心策略:遍历到第i个学生时,计算sum,如果sum>m则从前i-1个由大到小减,直到sum<m。所以在数据量很小时,可以排序后遍历,但现在为10^5显然不行。由题意只ti最多到100,我们是想每次都能找到当前最大的ti值,依次减。所以可以用一个数组countk[i]表示当前测试时间为k的学生有多少个,这样的话只用从大到小遍历100,而不是n了。

#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

int a[200020];
int cnt[200];

int main()
{
    int n,m;
    cin>>n>>m;
    far(i,0,n)
        scanf("%d",&a[i]);
    printf("0 ");
    int sum=a[0];
    cnt[a[0]]++;
    far(i,1,n)
    {
        sum+=a[i];
        if(sum>m)
        {
            int x=sum-m;
            int ans=0;
            for(int j=100;j>=1;--j)
            {
                int y=j*cnt[j];
                ans+=cnt[j];
                if(y>=x)
                {
                    int z=y-x;
                    ans-=z/j;
                    break;
                }
                x-=y;
            }
            printf("%d ",ans);
        }
        else
            printf("0 ");
        cnt[a[i]]++;
    }
}

D、Extra Element

theme:给定一个数组n,问删除其中哪个元素后,经过排序数组是等差数列。如果不存在,则输出-1。

 (2≤n≤2⋅10^5,−10^9≤bi≤10^9)

solution:等差数列最主要的就是公差,所以先排序,注意最后求的是下标,所以记录下原下标。首先我们得确定公差。考虑a[1]-a[0],所以先判断删除1,2个元素行不行,即两次遍历即可。如果不行,则可以确定公差d=a[1]-a[0],现在开始往后遍历相邻两项和是否为d,一旦不为,假设a[i+1]-a[i]!=d,则判断a[i+2]-a[i]是否为d(注意要判断i+2是否>=n),如果=d,则说明删除排序后i+1项,如果它之后任意两项的差都为公差,则满足条件,否则输出-1.

#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

struct _a
{
    int i,v;
    bool operator<(_a b)const
    {
        return v<b.v;
    }
}a[200010];
int b[200010];

int main()
{
    int n;
    cin>>n;
    far(i,0,n)
        scanf("%d",&a[i].v),a[i].i=i;
    if(n<=3)
    {
        printf("1\n");
        return 0;
    }
    sort(a,a+n);
    far(i,0,n)
        b[i]=a[i].v;
    int d=b[2]-b[1];
    int flag=1;
    far(i,2,n-1)
    {
        if(b[i+1]-b[i]!=d)
        {
            flag=0;
            break;
        }
    }
    if(flag)
    {
        printf("%d\n",a[0].i+1);
        return 0;
    }

    d=b[2]-b[0];
    flag=1;
    far(i,2,n-1)
    {
        if(b[i+1]-b[i]!=d)
        {
            flag=0;
            break;
        }
    }
    if(flag)
    {
        printf("%d\n",a[1].i+1);
        return 0;
    }

    flag=1;
    d=a[1].v-a[0].v;
    int ans=1;
    far(i,1,n-1)
    {
        if(b[i+1]-b[i]!=d)
        {
           // cout<<"1:"<<i<<endl;
            if(i==n-2)
                ans=a[n-1].i+1;
            else
            {
                if(b[i+2]-b[i]==d)
                {
                    for(int j=i+2;j<n-1;++j)
                    {
                       // cout<<"2:"<<j<<endl;
                        if(a[j+1].v-a[j].v!=d)
                        {

                            flag=0;
                            break;
                        }
                    }
                    if(flag)
                       ans=a[i+1].i+1;
                }
                else
                    flag=0;
            }
            break;
        }
    }
    if(!flag)
        printf("-1\n");
    else
        printf("%d\n",ans);

}
/*
5
8 4 2 6 5

10
5 5 5 5 5 5 3 5 5 5

8
1 -1 1 -1 1 -1 1 -1
*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值