Submission #405311

#TimeUsernameProblemLanguageResultExecution timeMemory
405311drogskolAliens (IOI16_aliens)C++17
0 / 100
1 ms292 KiB
#include <bits/stdc++.h>
using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define ALL(v) v.begin(),v.end()

//base:[Convex-Hull Trick - sataniC++](http://s...content-available-to-author-only...g.com/entry/2016/08/16/181331#fn-534591c8)
//追加する直線の傾きは単調(最小値なら傾きは単調減少、最大値なら傾きは単調増加)
template<typename T>
struct ConvecHullTrick {
  typedef pair<T,T> Line;
  vector<Line> lines; //直線(傾き,切片)
	bool isMonotonicX; //最小値(最大値)を求めるxが単調であるか
	function<bool(T l, T r)> comp; //最小/最大を判断する関数

	//flag:クエリは単調? compFunc:求めるのは最大値?
	ConvecHullTrick(bool flagX=0,bool compFunc=0):isMonotonicX(flagX){
    if(compFunc)comp=[](T l,T r){return l<=r;};
    else comp=[](T l,T r){return l>=r;};
	};

	//直線l1,l2,l3のうちl2が不必要であるかどうか
	bool check(Line l1,Line l2,Line l3){
		if(l1<l3)swap(l1,l3);
    T a1=l1.first,a2=l2.first,a3=l3.first,b1=l1.second,b2=l2.second,b3=l3.second;
		return (b3-b2)*(a2-a1)>=(b2-b1)*(a3-a2);
	}

	//直線y=ax+bを追加する 単調性から付け足すのは一番後ろで、不必要なやつが消えるまで一番後ろを消したら付け足す
	void add(T a, T b) {
		Line line(a,b);
		while(lines.size()>=2&&check(*(lines.end()-2),lines.back(),line))lines.pop_back();
		lines.emplace_back(line);
	}

	//linesのi番目の直線のxでの値
	T f(int i,T x) {
		return lines[i].first*x+lines[i].second;
	}

	//特定のlineのxでの値
	T f(Line line,T x) {
		return line.first*x+line.second;
	}

	//直線群の中でxの時に最小(最大)となる値を返す
	T get(T x){
    assert(lines.size());
		if(isMonotonicX){//最小値(最大値)クエリにおけるxが単調(昇順)
			int head=0;
			while(lines.size()-head>=2&&comp(f(head,x),f(head+1,x)))head++;
			return f(head,x);
		}
		else{
			int low=-1,high=lines.size()-1;
			while(high-low>1){
				int mid=(high+low)>>1;
				if(comp(f(mid,x),f(mid+1,x)))low=mid;
        else high=mid;
			}
			return f(high,x);
		}
	}
};

using ll=long long;
typedef pair<int,int> P;

ll square(int a){
  return a*(ll)a;
}

ll shortest(int n,int k,const vector<P>&v,ll t){//t:ラグランジュ双対のパラメータ
  ConvecHullTrick<ll> CHT(1,0);
  REP(i,n){
    ll D=( i ? CHT.get(v[i-1].second)+square(v[i-1].second) : 0LL );//[0,i)を撮る最小コスト
    if(i&&v[i-1].second>v[i].first)D-=square(v[i].first-v[i-1].second);
    ll a=-2*v[i].first,b=square(v[i].first)+t+D;
    CHT.add(a,b);
  }
  ll D=CHT.get(v[n-1].second)+square(v[n-1].second);
  return D-t*k;
}

ll take_photos(int n,int m,int k,vector<int> r,vector<int> c){
  vector<P> v,tmp(n);
  REP(i,n)tmp[i]={min(r[i],c[i])-1,max(r[i],c[i])};
  sort(ALL(tmp));
  for(P p:tmp){
    if(v.size()&&v.back().second>=p.second)continue;
    if(v.size()&&v.back().first==p.first)v.pop_back();
    v.push_back(p);
  }
  n=v.size();
  ll res=3e12;
  if(n<=k){
    res=0;
    for(int i=0;i<n;i++){
      res+=square(v[i].second-v[i].first);
      if(i&&v[i-1].second>v[i].first)res-=square(v[i-1].second-v[i].first);
    }
  }
  ll lt=-3e12,rt=3e12;//tの下限,上限
  while(rt-lt>2){
    //cout<<lt<<" "<<rt<<endl;
    ll t1=lt+(rt-lt)/3,t2=lt+(rt-lt)*2/3;
    if(shortest(n,k,v,t1)<shortest(n,k,v,t2))lt=t1;
    else rt=t2;
  }
  //cout<<"T"<<(lt+rt)/2<<endl;
  return shortest(n,k,v,(lt+rt)/2);
}

/*int main(){
  int n,m,k;cin>>n>>m>>k;
  vector<int> r(n),c(n);
  REP(i,n)cin>>r[i]>>c[i];
  cout<<take_photos(n,m,k,r,c)<<endl;
}*/
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...