CTU Open Contest 2019

CTU Open Contest


D.Beer Flood


E.Beer Game


F. Beer Marathon

題意:

在一條直線上有 N 個啤酒攤,這些啤酒攤的位置在直線上隨機擺放,題目要求是任何兩個 連續啤酒攤位之間的距離應完全相同,並等於指定的特定值 K。問每個啤酒攤最少移動多少米 可以使他們之間的距離是 K 值(儘量減少所有啤酒攤位移動的總米數

思路:

題目的最優解會對應一個起點,則函數爲單峯函數,因此可以三分。
因爲n<=1e6,k<=1e6,所以三分範圍爲[-1e12,1e12]
循環 100 次爲 1e8 時間複雜度,3 的 100 次方的精準度。

ps:
賽中以爲最優起點肯定在某個x[i]上,然後就三分下標了 (這種操作說起來挺傻逼的)。
還有就是以爲起點可以在中間,然後從中間向兩邊擴展(賽後纔想起這根本不符合常識)。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e6+6;
int x[maxm];
int n,k;
int check(int st){
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=abs(x[i]-st);
        st+=k;
    }
    return ans;
}
signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        scanf("%lld",&x[i]);
    }
    sort(x+1,x+1+n);
    int l=-1e12,r=1e12;
    int ans=1e18;
    for(int i=1;i<=100;i++){
        int mid=(l+r)/2;
        int midd=(mid+r)/2;
        int a=check(mid);
        int b=check(midd);
        if(a>b){
            l=mid;
        }else{
            r=midd;
        }
        ans=min(ans,min(a,b));
    }
    cout<<ans<<endl;
    return 0;
}

I.Sixpack


J.Beer Vision

題意:

給出n個點(x,y),這n個點是其中一些點按照一個向量<X,Y>平移之後得到的新點與原來點的並集。
問這樣的向量可能有多少個。

思路:

題意可轉化爲對於所有的集合中的點,滿足+x,+y 或-x,-y 至少有一個點也在集合中。問可以選出多少個這樣不同的 x 和 y。對每對點做差,滿足要求的 x,y 一定在差值中至少出現了 n/2(上取整)次。這樣的 x,y 顯然最多有 n 個。枚舉判斷是否合法即可,複雜度 O(n^2)。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e3+5;
int x[maxm],y[maxm];
map<pair<int,int>,int>mark;
map<pair<int,int>,int>xy;
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x[i]>>y[i];
        mark[{x[i],y[i]}]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            int xx=x[i]-x[j];
            int yy=y[i]-y[j];
            xy[{xx,yy}]++;
        }
    }
    int ans=0;
    for(auto i:xy){
        if(i.second>=(n+1)/2){
            int ok=1;
            int xx=i.first.first;
            int yy=i.first.second;
            for(int i=1;i<=n;i++){
                if(!mark[{x[i]-xx,y[i]-yy}]&&!mark[{x[i]+xx,y[i]+yy}]){
                    ok=0;
                    break;
                }
            }
            if(ok)ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章