This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub ttamx/cp-library
#define PROBLEM "https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary" #include "template.hpp" #include "convolution/max-plus-convolution.hpp" int main(){ cin.tie(nullptr)->sync_with_stdio(false); int n,m; cin >> n >> m; vector<int> a(n),b(m); for(auto &x:a){ cin >> x; x*=-1; } for(auto &x:b){ cin >> x; x*=-1; } auto c=max_plus_convolution_arbitary_convex(b,a); for(auto x:c){ cout << -x << " "; } }
#line 1 "verify/yosupo/convolution/min_plus_convolution_convex_arbitrary.test.cpp" #define PROBLEM "https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary" #line 1 "template.hpp" #include<bits/stdc++.h> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> using namespace std; using namespace __gnu_pbds; using ll = long long; using db = long double; using vi = vector<int>; using vl = vector<ll>; using vd = vector<db>; using pii = pair<int,int>; using pll = pair<ll,ll>; using pdd = pair<db,db>; const int INF=INT_MAX/2; const int MOD=998244353; const int MOD2=1000000007; const ll LINF=LLONG_MAX/2; const db DINF=numeric_limits<db>::infinity(); const db EPS=1e-9; const db PI=acos(db(-1)); template<class T> using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>; template<class T> using ordered_multiset = tree<T,null_type,less_equal<T>,rb_tree_tag,tree_order_statistics_node_update>; mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); mt19937_64 rng64(chrono::steady_clock::now().time_since_epoch().count()); #line 2 "convolution/max-plus-convolution.hpp" /** * Author: Teetat T. * Date: 2024-09-01 * Description: Max Plus Convolution. Find $C[k] = max_{i+j=k}\{A[i] + B[j]\}$. * Time: $O(N)$. */ // SMAWCK algorithm for finding row-wise maxima. // f(i,j,k) checks if M[i][j] <= M[i][k]. // f(i,j,k) checks if M[i][k] is at least as good as M[i][j]. // higher is better. template<class F> vector<int> smawck(const F &f,const vector<int> &rows,const vector<int> &cols){ int n=(int)rows.size(),m=(int)cols.size(); if(max(n,m)<=2){ vector<int> ans(n,-1); for(int i=0;i<n;i++){ for(int j:cols){ if(ans[i]==-1||f(rows[i],ans[i],j)){ ans[i]=j; } } } return ans; } if(n<m){ // reduce vector<int> st; for(int j:cols){ while(true){ if(st.empty()){ st.emplace_back(j); break; }else if(f(rows[(int)st.size()-1],st.back(),j)){ st.pop_back(); }else if(st.size()<n){ st.emplace_back(j); break; }else{ break; } } } return smawck(f,rows,st); } vector<int> ans(n,-1); vector<int> new_rows; for(int i=1;i<n;i+=2){ new_rows.emplace_back(rows[i]); } auto res=smawck(f,new_rows,cols); for(int i=0;i<new_rows.size();i++){ ans[2*i+1]=res[i]; } for(int i=0,l=0,r=0;i<n;i+=2){ if(i+1==n)r=m; while(r<m&&cols[r]<=ans[i+1])r++; ans[i]=cols[l++]; for(;l<r;l++){ if(f(rows[i],ans[i],cols[l])){ ans[i]=cols[l]; } } l--; } return ans; } template<class F> vector<int> smawck(const F &f,int n,int m){ vector<int> rows(n),cols(m); iota(rows.begin(),rows.end(),0); iota(cols.begin(),cols.end(),0); return smawck(f,rows,cols); } // Max Plus Convolution. // b must be convex, i.e. b[i]-b[i-1]>=b[i+1]-b[i]. template<class T> vector<T> max_plus_convolution_arbitary_convex(vector<T> a,const vector<T> &b){ if(a.empty()||b.empty())return {}; if((int)b.size()==1){ for(auto &x:a)x+=b[0]; return a; } int n=(int)a.size(),m=(int)b.size(); auto f=[&](int i,int j){ return a[j]+b[i-j]; }; auto cmp=[&](int i,int j,int k){ if(i<k)return false; if(i-j>=m)return true; return f(i,j)<=f(i,k); }; auto best=smawck(cmp,n+m-1,n); vector<T> ans(n+m-1); for(int i=0;i<n+m-1;i++){ ans[i]=f(i,best[i]); } return ans; } #line 4 "verify/yosupo/convolution/min_plus_convolution_convex_arbitrary.test.cpp" int main(){ cin.tie(nullptr)->sync_with_stdio(false); int n,m; cin >> n >> m; vector<int> a(n),b(m); for(auto &x:a){ cin >> x; x*=-1; } for(auto &x:b){ cin >> x; x*=-1; } auto c=max_plus_convolution_arbitary_convex(b,a); for(auto x:c){ cout << -x << " "; } }