HRBU 2021年暑期训练阶段四Day3

 

目录

A - Cow Acrobats

题目链接:

题意:

做法:

B - Dropping tests

题目链接:

题意:

做法:

C - K Best

题目链接:

题意:

做法:

D - Pyramid Split

题目链接:

题意:

做法:

E - Alignment

题目链接:

题意:

做法:

F - Longest Ordered Subsequence

题目链接:

题意:

做法:

G - 排序

题目链接:

做法:


A - Cow Acrobats

题目链接:

HRBU 2021年暑期训练阶段四Day3 - Virtual Judge

题意:

一堆牛牛策划逃跑,他们需要叠罗汉(建议不懂的同学可以百度)才能出逃,每一头牛牛都有一个重量值和一个力量值,如果要保证出逃成功,那么叠罗汉的时候下面的牛牛的力量值得比它上面所有牛牛的体重值大,问在叠罗汉成功的情况下最下面的牛牛的力量值和它承受的重量值的差值最大是多少

做法:

把每一头牛的力量和重量累加起来,之后再以这个和去排序,我们就能保证前面的牛牛要么力量大,要么体重大,或者两个都大,一定优先放在下面,最后遍历记录最大值就好了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
int N;
ll sum[maxn];
struct Node
{
    int W,S;
    ll sum;
}C[maxn];

bool cmp(Node a,Node b)
{
    return a.sum<b.sum;
}

int main()
{
    int maxx=INT_MIN;
    ios::sync_with_stdio(false);
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        cin>>C[i].W>>C[i].S;
        C[i].sum=C[i].W+C[i].S;
    }
    sort(C+1,C+N+1,cmp);
    sum[1]=0;
    for(int i=2;i<=N;i++)
        sum[i]=sum[i-1]+C[i-1].W;
    for(int i=1;i<=N;i++)
    {
        if(sum[i]-C[i].S>maxx)
            maxx=sum[i]-C[i].S;
    }
    cout<<maxx<<endl;
    return 0;
}

B - Dropping tests

题目链接:

https://vjudge.net/contest/454120#problem/B

题意:

按照题目中给定的公式,问能求出的最大值是多少

做法:

一个最大化平均值的操作,把平均值用来二分,然后将原题中的公式进行转换成一种累加的形式

设A=∑a[i],B=∑b[i],则A=r×B,A-r×B=0。所以为了求得最大的r,我们就要求使得A-rxB>0的最大的r,这样我们就可以另ci=ai-bi*r,然后对数组c进行排序即可(转载自大佬的博客

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
using namespace std;
typedef long long ll;
const int maxn=2e3+10;

bool cmp(double x, double y)
{
    return x>y;
}

int main()
{
    ios::sync_with_stdio(false);
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        if(n==0&&k==0)
            break;
        double a[maxn],b[maxn],sum[maxn];
        for(int i=0;i<n;i++)
            scanf("%lf",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%lf",&b[i]);
        double l=0.0,r=1.0,mid,tmp;
        while(r-l>1e-5)
        {
            tmp=0;
            mid=(l+r)/2;
            for(int i=0;i<n;i++)
                sum[i]=a[i]-mid*b[i];
            sort(sum,sum+n,cmp);
            for(int i=0;i<n-k;i++)
                tmp+=sum[i];
            if(tmp>0)
                l=mid;
            else
                r=mid;
        }
        int ans=(int)(mid*100+0.5);
        printf("%d\n",ans);
    }
    return 0;
}

C - K Best

题目链接:

HRBU 2021年暑期训练阶段四Day3 - Virtual Judge

题意:

给出n个珠宝,现在让选出m个,使得v(和)/m(和)相除得到的数字最大。
输出选择的m个珠宝。

做法:

该题思路有限,只能做到出题,不能做到完美解释这个题目

大佬博客(两种方法,第二种都没看到过)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int INF=1e6+10;
int n,k;
struct Node
{
    int v,w,id;
    double y;
    bool operator < (const Node& x) const
    {
        return y>x.y;
    }
}p[maxn];

bool judge(double x)
{
    for(int i=1;i<=n;i++)
        p[i].y=p[i].v-p[i].w*x;
    sort(p+1,p+n+1);
    double sum=0;
    for(int i=1;i<=k;i++)
        sum+=p[i].y;
    return sum>=0;
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].v,&p[i].w);
        p[i].id=i;
    }
    double l=0,r=INF;
    for(int i=0;i<100;i++)
    {
        double mid=(l+r)/2;
        if(judge(mid))
            l=mid;
        else
            r=mid;
    }
    for(int i=1;i<=k;i++)
    {
        if(i==1)
            printf("%d",p[i].id);
        else
            printf(" %d",p[i].id);
    }
    printf("\n");
    return 0;
}

D - Pyramid Split

题目链接:

HRBU 2021年暑期训练阶段四Day3 - Virtual Judge

题意:

一堆金字塔!要求一刀切之后上半部分的体积和与下半部分的体积和相同,问这一刀切在哪

做法:

图示:

 如图所示,这样的一个横截面就是我们所进行分析的图像,可以推导出下面这个公式

\frac{b}{B}=\frac{A-a}{A}

 其中b以及a为未知数,把a作为二分的对象,再带回式子中进行计算判断即可,注意当a>A时,就是未对金字塔进行切割哦,因为高度不够,最后需要用上圆锥的体积公式,详情代码里有

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int T,n,A[maxn],B[maxn];

bool check(int h)
{
    int i;
    double a,b;
    a=b=0;
    for(i=1;i<=n;i++)
    {
        a=a+A[i]*B[i]*B[i];//圆锥总体积
        int t=max((A[i]-h),0);
        ///判断你当前切的位置是否大于这个圆锥的高度
        ///0
        ///A-h
        b = b+t*1.0/A[i]*B[i]*t/A[i]*B[i]*t;
        ///b=b+1/3*(t*1.0/A[i]*B[i]*t/A[i]*B[i]*t)
    }
    return a >= 2*b;
    ///a/2.0>=b;
}

int Binary_search ( )
{
    int l=1,mid,r=1000;
    while(l<r)
    {
        mid=(l+r)>>1;
        if (check(mid))
            r=mid;
        else
            l=mid+1;
    }
    return l-1;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1; i<=n; i++)
            cin>>A[i];//整体圆锥高度
        for(int i=1; i<=n; i++)
            cin>>B[i];//底面边长
        int x=Binary_search();
        cout<<x<<endl;
    }
    return 0;
}
/**
圆锥的体积公式是:底面积*高
v=b*b*h*1/3
*/

E - Alignment

题目链接:

https://vjudge.net/contest/454120#problem/E

题意:

一个长官想让自己的士兵按照身高(由低到高再到低)进行一个排列,问需要最少出列几名士兵之后才能做到

做法:

一个标准的最长上升子序列,遍历两次序列,首先从前往后,接着从后往前,最后判断中点位置是否有两个人的存在

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
using namespace std;
typedef long long ll;
const int maxn=2e3+10;

int main()
{
    ios::sync_with_stdio(false);
    int n,Ls[maxn],Rs[maxn];
    float h[maxn];
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>h[i],Ls[i]=Rs[i]=0;
    for(int i=1;i<=n;i++)
    {
        int maxx=0;
        for(int j=1;j<=i;j++)
        {
            if(h[j]<h[i])
                Ls[i]=max(Ls[i],Ls[j]+1);
        }
    }
    for(int i=n;i>=1;i--)
    {
        int maxx=0;
        for(int j=n;j>=i;j--)
        {
            if(h[j]<h[i])
                Rs[i]=max(Rs[i],Rs[j]+1);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int tmp;
        for(int j=i;j<=n;j++)
        {
            if(i==j)
                tmp=1;
            else
                tmp=2;
            ans=max(ans,Ls[i]+Rs[j]+tmp);
        }
    }
    cout<<n-ans<<endl;
    return 0;
}

F - Longest Ordered Subsequence

题目链接:

HRBU 2021年暑期训练阶段四Day3 - Virtual Judge

题意:

最长的上升子序列的长度是多少

做法:

二分查找即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int N,a[maxn];

int slove(int l,int r,int num)
{
    int mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(a[mid]<=num)
            l=mid+1;
        else
            r=mid;
    }
    return l;
}

int main()
{
    ios::sync_with_stdio(false);
    int cnt=0;
    cin>>N;
    cin>>a[0];
    cnt++;
    for(int i=1;i<N;i++)
    {
        int x;
        cin>>x;
        if(x>a[cnt-1])
            a[cnt++]=x;
        else
        {
            int tmp=slove(0,cnt,x);
            a[tmp]=x;
        }
    }
    cout<<cnt<<endl;
    return 0;
}

G - 排序

题目链接:

 https://vjudge.net/contest/454120#problem/G

做法:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
string s;
int main()
{
    while(cin>>s)
    {
        ll a[maxn],b=0,j=0;
        int len=s.length();
        memset(a,0,sizeof(a));
        for(int i=0;i<len;i++)
        {
            if(s[i]!='5')
                b=b*10+(s[i]-'0');
            if((s[i]!='5')&&(s[i+1]=='5'||i==len-1))
            {
                a[j++]=b;
                //cout<<a[j-1]<<endl;
                b=0;
            }
        }
        if(j==len)
        {
            cout<<0<<endl;
            continue;
        }
        sort(a,a+j);
        for(int i=0;i<j-1;i++)
            cout<<a[i]<<" ";
        cout<<a[j-1]<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值