1. 程式人生 > >【Codeforces Round #509 (Div. 2)】A,B,C,D

【Codeforces Round #509 (Div. 2)】A,B,C,D

這是蒟蒻的真·第一場CF...所以其實升了1500+還是不錯吧?

題意:找包含給出的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;
}

題意:給出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;
}

題意:

  • 工作日持續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]]<<" ";
}

題意:

  • 一架飛機在地面以上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;
}

                                       ——時間劃過風的軌跡,那個少年,還在等你。