HRBU 2021暑期训练解题报告阶段三Day3

目录

A - 敌兵布阵

B - Sum of Consecutive Prime Numbers

C - 天上的星星

D - Graveyard Design

E - Exam in BerSU (hard version)

F - Maximum Sum

G - Pie


A - 敌兵布阵

题意:

中文你我?懂?

 

思路:

单点修改,区间查询 => 入门线段树√

  • 考察点:线段树,数据结构

代码:

//cin卡时间,关闭输入流
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+100;
struct node
{
    int l,r;
    int sum;
}tree[maxn*4];

int a[maxn];


inline void build(int i,int l,int r){   ///O(n)
    tree[i].l=l;
    tree[i].r=r;
    if(l==r){
        tree[i].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}

inline void update(int i,int l,int r,int x){  ///O(nlogn)  O(logn)
    if(tree[i].l==l&&tree[i].r==r){
        tree[i].sum+=x;
        return;
    }
    if(tree[i*2].r>=l) update(i*2,l,r,x);
    if(tree[i*2+1].l<=r) update(i*2+1,l,r,x);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}

inline int query(int i,int l,int r){  ///O(logn)
    if(tree[i].l>=l&&tree[i].r<=r)
        return tree[i].sum;
    if(tree[i].l>r||tree[i].r<l)
        return 0;
    int s=0;
    if(tree[i*2].r>=l) s+=query(i*2,l,r);
    if(tree[i*2+1].l<=r) s+=query(i*2+1,l,r);
    return s;
}

int main(){
    int t,cnt=0,x,y;
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        build(1,1,n);
        cout<<"Case "<<++cnt<<":"<<endl;
        string ss;
        while(cin>>ss){
            if(ss=="End")
                break;
            else{
                cin>>x>>y;
                if(ss=="Query")
                {
                    cout<<query(1,x,y)<<endl;
                }
                else if(ss=="Add")
                    update(1,x,x,y);
                else
                    update(1,x,x,-y);
            }
        }
    }
}

B - Sum of Consecutive Prime Numbers

题意:

一些正整数可以由连续的素数相加而成。
给定数字n,求出有多少种方案。

思路:

第一步:欧拉筛筛出10000之内的所有素数。

第二步:暴力枚举结果 / 进行尺取

  • 考察点:枚举,素数,思维,尺取

代码:

#include<iostream>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e4+500;
int prime[maxn]; ///prime[0]
bool is_prime[maxn];
void init(){    ///欧拉筛
    memset(is_prime,false,sizeof(is_prime));
    is_prime[0]=is_prime[1]=true;
    prime[0]=0;
    for(int i=2;i<=10000;i++){
        if(!is_prime[i])
            prime[++prime[0]]=i;
        for(int j=1;j<=prime[0];j++){
            if(i*prime[j]>10000) break;
            is_prime[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}

int main()
{
    init();
    int n;
    while(cin>>n&&n){
        int cnt=0;
        for(int i=1;i<=prime[0];i++){
            int sum=0;
            for(int j=i;j<=prime[0];j++){
                sum+=prime[j];
                if(sum>=n) break;
            }
            if(sum==n)
                cnt++;
        }
        cout<<cnt<<endl;
    }
}

C - 天上的星星

题意:

我麻了,但你们懂的8.

思路:

二维前缀和,求(0,0)~(i,j)的星星亮度和存储起来。

//a[i][j]:(i,j)处的星星亮度   sum[i][j]:(0,0)~(i,j)围成的矩形区域的总亮度
if(i>0) sum[i][j]+=sum[i-1][j];

if(j>0) sum[i][j]+=sum[i][j-1];

if(i>0&&j>0) sum[i][j]-=sum[i-1][j-1];

sum[i][j]+=a[i][j];

如何求(x,y)~(c,z)围成的矩形的亮度:

int ans=sum[c][z];

if(x) ans-=sum[x-1][z];

if(y) ans-=sum[c][y-1];

if(x&&y) ans+=sum[x-1][y-1]; //多减去一块补上
  • 考察点:二维前缀和,数学,思维

代码:

#include<bits/stdc++.h>
using namespace std;
int a[2050][2050]={0};
int sum[2050][2050]={0};  //sum[i][j]:sum[0][0]与sum[i][j]围成的矩形区域的亮度
int main()
{
    int n,x,y,w,q,c,z;
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>x>>y>>w;
        a[x][y]+=w;
    }
    for(int i=0; i<=2000; i++)
        for(int j=0; j<=2000; j++)
        {
            if(i>0)
                sum[i][j]+=sum[i-1][j];
            if(j>0)
                sum[i][j]+=sum[i][j-1];
            if(i>0&&j>0)
                sum[i][j]-=sum[i-1][j-1];
            sum[i][j]+=a[i][j];
        }
//    for(int i=0; i<=10; i++)
//    {
//        for(int j=0; j<=10; j++)
//            cout<<sum[i][j]<<" ";
//        cout<<endl;
//    }

    cin>>q;
    for(int i=1; i<=q; i++)
    {
        cin>>x>>y>>c>>z;
        int ans=sum[c][z];
        //cout<<ans<<endl;
        if(x)
            ans-=sum[x-1][z];
        if(y)
            ans-=sum[c][y-1];
        if(x&&y)
            ans+=sum[x-1][y-1];
        cout<<ans<<endl;
    }
}

D - Graveyard Design

题意:

给定一个数n,问有多少种方案满足:

连续的数的平方和等于n。

举例:2030=21^2+22^2+23^2+24^2。
输出区间元素个数与区间内的元素。

思路:

裸的尺取,尺取上限:sqrt(n)。中间记得记录答案,注意输出。

  • 考察点:尺取,思维,数学

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
struct node
{
    int l,r;
}a[maxn];  
int main()
{
    ll n;
    while(cin>>n){
        ll len=sqrt(n);
        ll l=1,r=1;
        ll sum=0;
        int cnt=0;
        while(l<=len){
            while(sum<n&&r<=len){
                sum+=r*r;
                r++;
            }
            if(sum<n) break;
            if(sum==n){
                a[++cnt].l=l;
                a[cnt].r=r;
                //cout<<a[cnt].l<<" "<<a[cnt].r<<endl;
            }
            sum-=l*l;
            l++;
        }
        cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++){
            cout<<a[i].r-a[i].l<<" ";
            for(int j=a[i].l;j<a[i].r-1;j++)
                cout<<j<<" ";
            cout<<a[i].r-1<<endl;
        }
    }
}

E - Exam in BerSU (hard version)

题意:

现在有一场考试,全场时长M分钟,一共有n个同学。
只有当第i名同学解完题目或者放弃做题的时候,第i+1名同学才能开始做题。每名同学需要ai的时间做题。

对于第i名同学来说,在他之前至少有多少人放弃考试他才能在规定时间内完成考试呢?

思路:

这个题其实十分简单,对当前已经考完试的同学贪心就好了。

首先统计时间,对于下一个同学,假设当前的时间为sum,这位同学的考试时间为T,存在以下两种情况:

  1. sum+T<=m                没有人会痛苦
  2. sum+T>m                  找到之前考试时间最长的那几个gdx,然后_________。

剩下的看代码吧。

  • 考察点:贪心,枚举,思维

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1e4+500;
int num[105];   ///num[i]:考试时间为i的同学人数
int main()
{
    int n,m;
    cin>>n>>m;
    ll sum=0,t;
    memset(num,0,sizeof(num));
    for(int i=1;i<=n;i++)
    {
        cin>>t;
        sum+=t;
        if(sum<=m)
            cout<<"0 ";
        else{
            ll sum2=sum;
            ll cnt=0;
            for(int j=100;j>0;j--){  ///贪心策略
                if(num[j]==0) continue;
                sum2-=num[j]*j;
                cnt+=num[j];
                if(sum2<=m){
                    cnt-=(m-sum2)/j; ///不能全部踢掉,踢掉最有必要的
                    break;
                }
            }
            cout<<cnt<<" ";
        }
        num[t]++;
    }
    cout<<endl;
}

F - Maximum Sum

题意:

求一个矩阵的子矩阵,使得这个子矩阵的和最大。输出这个和。

思路:

暴力枚举出所有可能。

  • 考察点:暴力,枚举,矩阵求和,最大子序列求和

代码:

///111
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;

int a[150][150];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        cin>>a[i][j];
    int ans=0;
    for(int i=1;i<=n;i++) 
    for(int j=i;j<=n;j++){    ///i j形成竖着的两面墙
        int sum=0;
        for(int k=1;k<=n;k++) ///k遍历行
        {
            for(int c=i;c<=j;c++)
                sum+=a[k][c];
            if(sum<0) sum=0;
            ans=max(sum,ans);
        }
    }
    cout<<ans<<endl;
    return 0;
}

G - Pie

题意:

你在过生日,你有m个朋友,你有n个馅饼,每个馅饼都是圆柱体,高相同但半径不同
第i个馅饼的半径为ai
要保证每个人得到的馅饼体积相等。

问:每个人最后可以拿到的馅饼最大是多少?

思路:

二分答案模板题。

  • 考察点:二分,思维

  • 坑点:精度要求较高

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define inf 0x3f3f3f3f
#define PI acos(-1.0) 
using namespace std;
const int maxn=1e4+500;
double a[maxn];
int n,m;
bool check(double x){
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=(int)(a[i]/x);
        if(ans>=m)
            return true;
    }
    return false;
}
int main()
{
    int t,x;
    scanf("%d",&t);
    while(t--){
        double l=0,r=0;
        scanf("%d%d",&n,&m);
        m++;                   ///还要算上自己的
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            a[i]=PI*x*x*1.0;
            r+=a[i];
        }
        r/=m;
        while((r-l)>1e-6){
            double mid=(l+r)/2;
            if(check(mid)){
                l=mid;
            }
            else
                r=mid;
        }
        printf("%.4lf\n",l);
    }
}

おすすめ

転載: blog.csdn.net/qq_45750296/article/details/119718483