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;
}