This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
//Convex Hull Trick, verified on CF319C (319 is ID)
import java.io.*; import java.util.*;
public class sequence{
static class FastReader
{
BufferedReader br;
StringTokenizer st;
public FastReader()
{
br = new BufferedReader(new
InputStreamReader(System.in));
}
String next()
{
while (st == null || !st.hasMoreElements())
{
try
{
st = new StringTokenizer(br.readLine());
}
catch (IOException e)
{
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt()
{
return Integer.parseInt(next());
}
}
static int[] M;
static long[] B;
static int[] ind;
static int pointer=0;
static short[][] ch; static boolean[][] b1; static boolean[][] b2;
static int N;
static int sz;
public static void main(String[] args){
FastReader br=new FastReader();
N=br.nextInt(); int K=br.nextInt();
int[] s=new int[N];
long[] dp=new long[N];
long[] dp2=new long[N];
ch=new short[N][K]; b1=new boolean[N][K];b2=new boolean[N][K];
s[0]=br.nextInt(); for(int i=1;i<N;i++){s[i]=s[i-1]+br.nextInt(); }
//System.out.println(Arrays.toString(s));
for (int i = 0; i < K; i++) {
M=new int[N];
B=new long[N];
ind=new int[N]; sz=0;
add(s[0],-(long)s[0]*s[0],i);
for (int j = 1; j < N; j++) {
dp2[j]=query((long)s[j],N*i+j);
add(s[j], dp[j]-(long)s[j]*s[j],Math.max(j,i));
//System.out.println(M);
//System.out.println(B);
}
for (int j = 0; j < N; j++) {
dp[j]=dp2[j];
}
//System.out.println(Arrays.toString(dp));
}
//System.out.println(Arrays.toString(dp));
System.out.println(dp[N-1]);
StringBuilder sb=new StringBuilder();
int[] arl=new int[K];
int cur=N-1;
for (int i = K-1; i >=0; i--) {
if(b1[cur][i] && b2[cur][i])cur=(int) 4*ch[cur][i]+3;
else if(b1[cur][i]) cur=(int) 4*ch[cur][i]+1;
else if(b2[cur][i]) cur=(int) 4*ch[cur][i]+2;
else cur=(int) 4*ch[cur][i];
arl[i]=cur+1;
}
//StringBuilder is actually quite memory consuming
for (int i = 0; i <K; i++) {
System.out.print(arl[i]+" ");
}
//System.out.println(sb.toString());
}
public static boolean bad(int l1, int l2, int l3){//Using doubles to prevent overflow
return (M[l1]-M[l3])*((double)B[l2]-B[l1])>=(M[l1]-M[l2])*((double)B[l3]-B[l1]);
//Intersection of l1 and l3 must be ABOVE l2
//For l2 to be added
//l1.m>l2.m>l3.m, as sum is strictly increasing
}
public static void add(int m, long b, int i){
M[sz]=m; B[sz]=b; ind[sz]=i; sz++;
while(sz>=3 && bad(sz-3,sz-2,sz-1)){
M[sz-2]=m; B[sz-2]=b; ind[sz-2]=i; sz--;
}
}
public static long query(long x, int j){
if(pointer>=sz){pointer=sz-1;}
while(pointer<sz-1 &&
M[pointer+1]*x+B[pointer+1] > M[pointer]*x+B[pointer]){
pointer++;
}
ch[j%N][j/N]=(short)(ind[pointer]/4);
if(ind[pointer]%2==1){
b1[j%N][j/N]=true;
}
if(ind[pointer]%4>=2){
b2[j%N][j/N]=true;
}
return M[pointer]*x+B[pointer];
}
}
//Debugging:
//Are you sure your algorithm is correct?
//Bounds: long
//Special cases: n=0,1?
//Make sure you remove your debugging code before you submit!
# | 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... |