제출 #406677

#제출 시각아이디문제언어결과실행 시간메모리
406677drogskolAliens (IOI16_aliens)C++17
100 / 100
285 ms8400 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; //最小/最大を判断する関数 int head=0; //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が単調(昇順) while(lines.size()<=head)head--; 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; using ld=long double; static const ld GRATIO = 1.6180339887498948482045868343656; 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){ //[0,i)の最小コストをDとする //[i,j]を囲うような正方形を考えると、これの大きさは(v[j].se-v[i].fi)^2 = v[j].se^2 -2v[j].se v[i]fi + v[i].se^2 //また、v[i-1].se>v[i].fiの時はi-1までの正方形との重複が(v[i-1].se-v[i].fi)^2 //ここにラグランジュ変数のtを足す必要がある //したがって、(-2v[i].fi)x + t+D+v[i].se^2 -(v[i-1].se-v[i].fi)^2 を付けてあげるようにすると、jまでの最小値がget(v[j].se)+v[j].se^2になる //v[i].fiは単調増加なので傾きは単調減少 v[i].seも単調増加にしてるのでクエリも単調増加 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-1].second-v[i].first); 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(); REP(i,n-1){ assert(v[i].first<v[i+1].first); assert(v[i].second<v[i+1].second); } if(n<=k){ ll res=0; //cout<<"N"<<n<<endl; //for(P p:v)cout<<p.first<<" "<<p.second<<endl; 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); } return res; } ll lt=-3e12,rt=3e12; ll t1=((ld)lt*GRATIO+(ld)rt)/(1.0+GRATIO),t2=((ld)lt+(ld)rt*GRATIO)/(1.0+GRATIO); ll va1=shortest(n,k,v,t1),va2=shortest(n,k,v,t2); while(rt-lt>30){ if(va1<va2){ lt=t1; t1=t2; va1=va2; t2=((ld)lt+(ld)rt*GRATIO)/(1.0+GRATIO); va2=shortest(n,k,v,t2); } else{ rt=t2; t2=t1; va2=va1; t1=((ld)lt*GRATIO+(ld)rt)/(1.0+GRATIO); va1=shortest(n,k,v,t1); } } while(rt-lt>2){ 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; } */

컴파일 시 표준 에러 (stderr) 메시지

aliens.cpp: In instantiation of 'T ConvecHullTrick<T>::get(T) [with T = long long int]':
aliens.cpp:85:37:   required from here
aliens.cpp:51:25: warning: comparison of integer expressions of different signedness: 'std::vector<std::pair<long long int, long long int>, std::allocator<std::pair<long long int, long long int> > >::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
   51 |       while(lines.size()<=head)head--;
      |             ~~~~~~~~~~~~^~~~~~
#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...