Codeforces Round #509 (Div. 2) A,B,C,D 题解

版权声明:https://blog.csdn.net/flora715 https://blog.csdn.net/flora715/article/details/82731940

这是蒟蒻的真·第一场CF...所以其实升了1500+还是不错吧?

A. Heist

题意:找包含给出的n个数的最短连续序列,输出新加入的数的最小个数。

分析:排序+扫描即可。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ll;

ll a[5019];

int main(){
    ll n,ans=0; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    for(int i=2;i<=n;i++)
        ans+=a[i]-a[i-1]-1;
    cout<<ans<<endl;
}

B. Buying a TV Set

题意:给出a,b,x,y,计算正整数w和h的对数,使得w≤a,h≤b,w/h=x/y。

分析:对于x、y,求二者的gcd(最大公约数),得出约分后的w/h,

          确定a、b能包含的w、h倍数上界即可。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ll;

//计算正整数w和h的对数,w≤a,h≤b,w/h=x/y

ll gcd(ll a,ll b){
    ll r;
    while(b>0){ r=a%b; a=b; b=r; }
    return a;
}

int main(){
    ll a,b,x,y,ans=0; cin>>a>>b>>x>>y;
    ll gcds=gcd(x,y); ll dx=x/gcds,dy=y/gcds;
    ll cnt=min((ll)a/dx,(ll)b/dy);
    cout<<cnt<<endl;
}

C. Coffee Break

题意:

  • 工作日持续m分钟。期间有n分钟可以选择喝咖啡:a1,a2,......每次一分钟。
  • 每天的任意两次喝咖啡至少间隔d分钟。希望在最短时间内完成n次咖啡时间。
  • 对于每个给定的分钟,确定一天,在此期间Monocarp应该在这一分钟喝咖啡。
  • 你必须尽量减少花费的天数。 并输出每个时间对应的天数。

分析:用set维护min元素,增加天数判断可行性即可,注意每次喝咖啡需要一分钟。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef unsigned long long ll;

/*【C】
工作日持续了m分钟。工作期间有n分钟可以选择喝咖啡:a1,a2,......每次一分钟。
每天的任意两次喝咖啡至少间隔d分钟。 希望在最短的工作日内完成这些n次咖啡休息时间。
对于每个给定的分钟,确定一天,在此期间Monocarp应该在这一分钟喝咖啡休息。
你必须尽量减少花费的天数。 并输出每个时间对应的天数。 */

ll a[200009];

map<int,int> maps;
set<int> ss;

int main(){
    ll n,m,d; cin>>n>>m>>d;
    for(ll i=1;i<=n;i++){
        cin>>a[i]; maps[a[i]]=0; ss.insert(a[i]);
    }
    int ans=1,cnt=0; 
    while(!ss.empty()){
        set<int>::iterator it=ss.lower_bound(cnt);
        if(it==ss.end()) cnt=0,ans++;
        else{ cnt=*it+1+d, maps[*it]=ans, ss.erase(it); }
    }
    cout<<ans<<endl; 
    for(ll i=1;i<=n;i++) cout<<maps[a[i]]<<" ";
}

D. Glider

题意:

  • 一架飞机在地面以上h米的恒定高度飞行。
  • 从飞机上跳下后,飞行员将飞向与飞机相同的方向,与x轴平行。
  • 每秒覆盖一个距离单位。当然,他也会下降,y坐标每秒减少一个单位。
  • 在某些段上有上升的气流,每个这样的段由两个数字x1、x2表示。
  • 没有两个部分共享任何共同点。当滑翔机在其中一个区段内时,他不会下降。

  • 如图:在1处跳出,他将在10点停止。在2点跳出,他将在12点停止。
  • 如果滑翔机可以选择任何整数坐标从飞机上跳起并开始飞行,
  • 则确定沿着Ox轴从滑翔机飞行开始的点到飞行结束点的最大距离。
  • 接触地面后将完全停止,因此如果第二个坐标为0,则无法滑过上升的气流段。

分析:维护两个sum数组。sum1[ ]表示气流段包含距离的前缀和,

          sum2[ ]表示非气流段包含距离的前缀和(可以不用,只是为了处理方便)。

          用双指针的方法维护head、tail,按照转移方程:

ans=max(ans,h+sum1[tail]-max(0,sum1[head-1]));

           进行转移。注意双指针的起点和变化模式。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef unsigned long long ll;

/*【D】*/

ll sum1[200019],sum2[200019];

int main(){
    ll n,h,le,ri,lastt=0; cin>>n>>h;
    for(ll i=1;i<=n;i++){
        cin>>le>>ri; sum1[i]=sum1[i-1]+ri-le;
        sum2[i]=sum2[i-1]+le-lastt; lastt=ri;
    } ll head=0,tail=1,ans=h;
    while(head<=n&&tail<=n){
        while(sum2[tail]-sum2[head]<h&&tail<=n){
            ans=max(ans,h+sum1[tail]-max((ll)0,sum1[head-1])); tail++;
        } head++;
    } cout<<ans<<endl;
}

                                       ——时间划过风的轨迹,那个少年,还在等你。

猜你喜欢

转载自blog.csdn.net/flora715/article/details/82731940