HRBU 2021暑期训练解题报告阶段四Day2

目录

A - Drying

B - Garland

C - How Many Tables

D - Can you solve this equation?

E - CD

F - Monthly Expense

G - Aggressive cows


A - Drying

题意:

最让HSQ学长头疼的就是洗衣服了。
洗完之后,每件衣服都有一定单位水分ai。
在不使用烘干器的情况下,每件衣服每分钟自然流失1个单位水分。
但如果使用了烘干机则每分钟流失K个单位水分。
令人遗憾是HSQ所在的宿舍楼只有1台烘干机,而每台烘干机同时只能烘干1件衣服。
请问要想烘干N件衣服最少需要多长时间?

思路:

我们二分最后的时间t。

1.当k==1时,风干和脱干就没啥区别了,特判一次。

2.当k!=1时,二分时间:

  • 假设时间为T,所有水分小于T的就让他自然风干就好了;
  • 水分大于T的需要使用烘干机,假设需要的时间为x,则(T-x)+k*x>=a[i],公式变形为x=ceil(a[i]-T)*1.0/(k-1)。
  • 考察点:二分,思维,数学

  • 坑点:int过不去

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
ll a[maxn];
int n;
ll k,maxx=-1;
bool check(ll mid)
{
    ll t=0;
    for(int i=1;i<=n;i++){
        if(a[i]>mid)
            t+=ceil((a[i]-mid)*1.0/(k-1));
    }
    return t<=mid;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        maxx=max(a[i],maxx);
    }
    scanf("%lld",&k);
    if(k==1){
        printf("%lld\n",maxx);
    }
    else{
        ll l=1,r=maxx;
        while(l<r){
            ll mid=(l+r)/2;
            if(check(mid))
                r=mid;
            else
                l=mid+1;
        }
        printf("%lld\n",l);
    }
}

B - Garland

题意:

给定推导式:Hi = (Hi-1 + Hi+1)/2 - 1,并给出n和H1的值。所有的Hi>=0。
求Hn的最小值。

思路:

首先,公式变形:

 接下来,我们带入i==2:

 其中下划线标注的为已知量,而H3的值由H2决定,以此类推。最终我们发现,我们其实是求H2的最小值,这个最小值会使后面的H3~Hn保证最小并且满足条件。

注意:我们是在二分H2的值,但是答案要求的是Hn的值。

  • 考察点:二分,数学

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int n;
double A,ans;

bool check(double mid)
{
    double now_h=A,h=mid;
    for(int i=3;i<=n;i++){
        double tmp=h;
        h=2*h-now_h+2;
        now_h=tmp;
        if(h<1e-9)
            return false;
    }
    ans=h;
    return true;

}
int main()
{
    scanf("%d",&n);
    scanf("%lf",&A);
    double l=0,r=100000;
    ans=0;
    while(r-l>1e-9){
        double mid=(l+r)/2;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }
    printf("%.2f\n",ans);
}

C - How Many Tables

题意:

你邀请了N个朋友来聚会 ,在他们之中有M个关系:
x y  :代表x和y是好朋友。
如果x,y是朋友,y,z是朋友,则认为xyz都是朋友(关系的传递)
你希望朋友应该坐在一起,这样就不会出现一些问题
请问最少要准备多少张桌子?

思路:

并查集模板题。

  • 考察点:并查集

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1050;

int fa[maxn];

void init(int n)
{
    for(int i=1;i<=n;i++)
        fa[i]=i;
}

int findf(int n)
{
    while(fa[n]!=n)
        n=fa[n];
    return n;
}

void join(int x,int y)
{
    int fx=findf(x),fy=findf(y);///fx:1 fy:3
    if(fx!=fy)
        fa[fy]=fx;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m,x,y;
        cin>>n>>m;
        init(n);
        for(int i=1;i<=m;i++){
            cin>>x>>y;
            join(x,y);
        }
        int cnt=0;
        for(int i=1;i<=n;i++)
            if(fa[i]==i)
            cnt++;
        cout<<cnt<<endl;
    }
}

D - Can you solve this equation?

题意:

给定方程式 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y。
现给出Y的值,求X。

思路:

二分答案模板题。

  • 考察点:二分,数学

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
double cal(double x)
{
    return 8*pow(x,4)+7*pow(x,3)+2*pow(x,2)+3*x+6;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        double y;
        scanf("%lf",&y);
        double l=0,r=100;
        if(cal(l)>y||cal(r)<y)
            printf("No solution!\n");
        else{
            double mid=(l+r)/2;
            while(fabs(cal(mid)-y)>1e-6){
                if(cal(mid)>y) r=mid;
                else l=mid;
                mid=(l+r)/2;
            }
            printf("%.4lf\n",mid);
        }
    }
}

E - CD

题意:

给定递增序列A与递增序列B,请问B中有多少元素在A中出现?

思路:

二分查找模板题。

  • 考察点:二分

  • 坑点:map会ME,不关输入流会TE

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
int a[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n,m,x;
    while(cin>>n>>m&&n&&m){
        for(int i=0;i<n;i++)
            cin>>a[i];
        int cnt=0,x;
        for(int i=0;i<m;i++){
            cin>>x;
            if(binary_search(a,a+n,x))
                cnt++;
        }
        cout<<cnt<<"\n";
    }
}

F - Monthly Expense

题意:

给出农夫在n天中每天的花费,要求把这n天分作m组,每组的天数必然是连续的。
要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值。

思路:

二分的又一经典问题:最小化最大值。

我们对最大值进行二分,假设最大值为x,我们可以将n天分成Y组。

1.Y>m  ==>  x过小

2.Y<m  ==> x过大

3.Y==m ==> x合适

  • 考察点:二分答案,思维

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int a[maxn];
int n,m;
bool check(int x)
{
    int cnt=1;
    int sum=0;
    for(int i=1;i<=n;i++){
        if(sum+a[i]<=x)
            sum+=a[i];
        else{
            sum=a[i];
            cnt++;
        }
    }
    return cnt>m;
}
int main()
{
    cin>>n>>m;
    int l=0,r=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        r+=a[i];
        l=max(a[i],l);
    }
    //cout<<l<<" "<<r<<endl;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
            l=mid+1;
        else
            r=mid-1;
    }
    cout<<r<<endl;
}

G - Aggressive cows

题意:

农夫养了C头牛,牛与牛之间很可能会打架,所以农夫打算把他们分开管理。
这里一共有n个牛棚,给出从左到右的坐标。
农夫想知道在安置好所有牛之后,牛牛们之间的最短距离的最大值是多少?
 

思路:

同F题,最大化最小值类型,对这个最短距离进行二分。

假设当前最短距离为x,算出可以安置的牛的个数Y。

1.Y>C  ==>  x过小

2.Y<C  ==> x过大

3.Y==C ==> x合适

代码:

///不关输入流会TE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int n,c;
int a[maxn];
bool check(int x)
{
    int cnt=1,pos=0;
    for(int i=1;i<n;i++)
        if(a[i]-a[pos]>=x)
        pos=i,cnt++;
    return cnt>=c;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>c;
    for(int i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);
    int l=0,r=a[n-1]-a[0];
    while(l<r){
        int mid=(l+r)/2;
        if(check(mid))
            l=mid+1;
        else
            r=mid;
    }
    cout<<l-1<<"\n";
}

おすすめ

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