This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
// moreflags=grader.cpp
// it's too late.
#include "aliens.h"
// 15
#include<algorithm>
#include<map>
#include<cmath>
#include<cstdint>
#include<climits>
#include<cfloat>
#if not LOCAL
#define NDEBUG
#endif
#include<cassert>
long long take_photos(int n, int m, int numPhoto, std::vector<int> r, std::vector<int> c) {
std::vector<std::pair<int, int>> points(r.size());
for(int index=0; index<(int)r.size(); ++index)
points[index]=std::minmax({r[index], c[index]});
std::sort(begin(points), end(points),
[&](auto first, auto sec){return first.first!=sec.first ? first.first<sec.first: first.second>sec.second;
});
{ // keep only extreme points
auto out=points.begin()+1;
std::for_each(out, points.end(),[&](auto it){
assert(it.first>=out[-1].first);
if(it.second>out[-1].second){
assert(it.first>out[-1].first);
*out++=it;
}
});
points.erase(out, points.end());
}
r.clear(); c.clear(); n=-1;
auto const square=[&](int it)->int64_t{return (int64_t)it*it;};
auto const check=[&](double slope)->std::pair<int64_t, int>{
std::vector<std::pair<double, int>> value(points.size()+1);
value[0]={0, 0};
auto const t=[&](int last)->double{
return value[last].first
-(double)square(last==0 ? 0: std::max(0, points[last-1].second-points[last].first+1))
+(double)square(points[last].first);
};
struct Item{double t; int numPhoto;};
struct IntComparator;
struct Query{
int slope;
std::map<int, Item, IntComparator> const& hull;
double operator()(int u, Item item)const{
return item.t + u* slope;
}
double operator()(typename std::map<int, Item>::value_type const& x)const{
return (*this)(x.first, x.second);
}
};
struct IntComparator
//: std::less<int>
{
// !?!?
using is_transparent=int;
bool operator()(Query first, int sec) const{
auto const iterator=first.hull.find(sec);
assert(iterator!=first.hull.end());
auto const next=std::next(iterator);
return next==first.hull.end() or first(*iterator)<=first(*next);
}
bool operator()(int first, int sec) const{
return first<sec;
}
/*
bool operator()(int sec, Query first) const{
return not (*this)(first, sec);
}
*/
};
std::map<int, Item, IntComparator> hull;
auto const add=[&](int pos)->void{
int const u=points[pos].first; double const t_=t(pos);
auto const [iterator, inserted]=hull.insert({u, {t_, value[pos].second}});
if(not inserted){
if(t_>=iterator->second.t) return;
iterator->second.t=t_;
}
assert(iterator->second.t==t_);
auto const bad=[&](auto iterator){
auto [u1_, i1]=*std::prev(iterator);
auto [u2_, i2]=*iterator;
auto [u3_, i3]=*std::next(iterator);
assert(u1_<u2_); assert(u2_<u3_);
auto const u1=u1_-u2_, u3=u3_-u2_;
double const t1=i1.t-i2.t;
double const t3=i3.t-i2.t;
return u3*t1-u1*t3<=0;
};
if(iterator!=hull.begin() and std::next(iterator)!=hull.end() and bad(iterator)){
hull.erase(iterator);
return;
}
while(std::next(iterator)!=hull.end() and
std::next(std::next(iterator))!=hull.end() and
bad(std::next(iterator)))
hull.erase(std::next(iterator));
while(iterator!=hull.begin() and std::prev(iterator)!=hull.begin() and
bad(std::prev(iterator)))
hull.erase(std::prev(iterator));
};
auto const query=[&](double slope){
std::pair<double, int> cur{DBL_MAX, 0};
/*
for(auto [u, item]: hull){
cur=std::min(cur, std::make_pair(
item.t + u* slope
, item.numPhoto +1));
}
*/
Query q{slope, hull};
auto iterator=hull.upper_bound(q);
if(iterator==hull.end()) --iterator;
//auto [u, item]=*iterator;
cur=std::make_pair(q(*iterator) , iterator->second.numPhoto +1);
return cur;
};
add(0);
for(int pos=1; ; ++pos){
auto& cur=value[pos];
cur={DBL_MAX, 0};
double const tmp2=-double(points[pos-1].second+1)*2;
/*
for(int last=0; last<pos; ++last){
cur=std::min(cur, std::make_pair(
(double)t(last) + points[last].first * tmp2
, value[last].second+1));
}
*/
cur=query(tmp2);
cur.first+=tmp2*tmp2/4+slope;
if(pos==(int)points.size()) break;
add(pos);
}
auto const [result, resultf]=value[points.size()];
return {(int64_t)std::round(result-resultf*slope), resultf};
};
// the numPhoto>=(int)points.size() case can be special-handled
double slope1=0;
auto [v1, nf1]=check(slope1);
if(numPhoto>=nf1) return v1;
assert(nf1>=(int)points.size());
double slope2; int64_t v2; int nf2;
for(slope2=1;; slope2*=2){
std::tie(v2, nf2)=check(slope2);
if(nf2<=numPhoto) break;
}
while(true){
assert(nf2<=numPhoto); assert(numPhoto<=nf1);
if(nf1==numPhoto and nf2==numPhoto){
assert(v1==v2);
return v1;
}
int64_t const lower=(int64_t)std::ceil(
std::max(
(double)v1+slope1*(nf1-numPhoto),
(double)v2+slope2*(nf2-numPhoto)
)-1e-12);
assert(nf1>nf2);
int64_t const upper=(v1*(numPhoto-nf2)+v2*(nf1-numPhoto))/(nf1-nf2);
assert(upper>=0);
assert(lower<=upper);
if(lower==upper) return lower;
assert(nf2<numPhoto); assert(numPhoto<nf1);
auto const slope3=(slope1+slope2)/2;
auto const [v3, nf3]=check(slope3);
(nf3<=numPhoto ? std::tie(v2, nf2, slope2): std::tie(v1, nf1, slope1))=std::tuple(v3, nf3, slope3);
}
}
Compilation message (stderr)
aliens.cpp: In lambda function:
aliens.cpp:130:12: warning: narrowing conversion of 'slope' from 'double' to 'int' [-Wnarrowing]
130 | Query q{slope, hull};
| ^~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |