Xây dựng lưới điện


22

Các thách thức

Có N thành phố thẳng hàng. Thành phố thứ i nằm hàng A[i]km bên phải gốc. Không có hai thành phố sẽ ở cùng một nơi.

Bạn sẽ xây dựng một mạng lưới điện với một số nhà máy điện. Các nhà máy điện phải được xây dựng bên trong một thành phố. Tuy nhiên, bạn chỉ được phép xây dựng K(<N) nhà máy điện, vì vậy sẽ có một số thành phố không có nhà máy điện trong đó. Đối với mỗi thành phố không có nhà máy điện, bạn phải xây dựng một cáp giữa nó và thành phố và thành phố gần nhất có nhà máy điện .

Ví dụ, nếu có ba thành phố nằm ở vị trí 0, 1, 2, và chỉ có thành phố tại 0có một nhà máy điện, bạn cần phải xây dựng hai dây cáp, một từ 2để 0(2km) và người kia từ 1đến 0(1km), có tổng chiều dài 3km .

Cho Kvà vị trí của các thành phố ( A), bạn nên tính toán số km cáp tối thiểu bạn cần để xây dựng lưới.

Ví dụ

K = 1, A = [0, 2, 4, 6, 8] : 12 
# build power plant in the city at position 4, total length = 4 + 2 + 0 + 2 + 4 = 12

K = 3, A = [0, 1, 10, 11, 20, 21, 22, 30, 32] : 23
# build power plants in cities at positions 0, 10 and 22

K = 5, A = [0, 1, 3, 6, 8, 11, 14] : 3
# build power plants in all cities except those at positions 0, 3

K = 6, A = [0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84] : 49

Thông số kỹ thuật

  • Bạn nên thực hiện một hàm hoặc một chương trình, trong đó có một số nguyên dương Kvà một danh sách các số nguyênA dưới mọi hình thức, và xuất / trả về một số nguyên biểu thị câu trả lời.

  • A được sắp xếp theo thứ tự tăng dần và tất cả các yếu tố là số nguyên không âm.

  • A[0] = 0A[N-1] sẽ không quá 1000N.

  • Lưu ý rằng đầu ra sẽ có cường độ 1000N 2 , vì vậy trong trường hợp lớn hơn, bạn có thể cần số nguyên 64 bit trong một số ngôn ngữ.

  • Đa luồng không được phép (Tôi sẽ đặt mối quan hệ của chương trình của bạn thành 1 lõi khi đánh giá). Tối ưu hóa trình biên dịch (như-O2 trong C) được cho phép.

Chấm điểm

  • Tôi sẽ đặt mã thời gian của bạn trên máy tính của tôi (Ubuntu 16.04 với bộ xử lý Intel i7-3770S) với kích thước khác nhau của các cặp thử nghiệm. Cụ thể, tôi sẽ tạo ra một số testcase với N = floor (2 x / 5 ) trong đó x là số nguyên dương.
    Điểm của bạn sẽ là giá trị x của mẫu thử nhỏ nhất mà chương trình của bạn sử dụng hơn 10 giây hoặc 1 GiB bộ nhớ hoặc không đưa ra câu trả lời đúng.

    • Câu trả lời với số điểm cao nhất sẽ thắng. Nếu hai câu trả lời có cùng số điểm, câu trả lời trước đó sẽ thắng.
  • Tất cả các chương trình sẽ được đánh giá bởi cùng một bộ testcase.

  • Hãy đăng bài của bạn. Giải thích về thuật toán của bạn được khuyến khích.

Tiền thưởng

Đây là chương trình C ++ của tôi, nó đạt 108 điểm . Bạn có thể xác minh thông báo SHA-256 9a87fa183bad1e3a83d2df326682598796a216b3a4262c32f71dfb06df12935dtheo toàn bộ đoạn mã (không có chân trang) trong liên kết.

Thuật toán kết hợp tìm kiếm nhị phân và tối ưu hóa của Knuth để tìm ra hình phạt chính xác của từng nhà máy để có được số lượng mong muốn. Độ phức tạp là O (N log N log A [N-1]). Tôi đã rất ngạc nhiên khi chương trình đạt điểm cao hơn giải pháp O (N log A [N − 1]) của Anders Kaseorg . Có lẽ là do thực tế là trường hợp đăng nhập trong tối ưu hóa của Knuth sẽ không xảy ra.

Lưu ý rằng thách thức này giống như Bưu điện IOI 2000 . Tuy nhiên, các ràng buộc ban đầu là N <= 300 và K <= 30.


2^^(x/5): nghĩa là gì ? bạn chỉ có thể cung cấp một giới hạn trên cho N?
Setop

1
@ Setop Ví dụ: nếu chương trình của bạn có thể xử lý N=21( = floor(2^(22/5)) )trong 10 giây, nhưng không thể xử lý N=24( = floor(2^(23/5)) ), thì 23 sẽ là điểm số. Tôi đã không sử dụng giới hạn trên, vì sự khác biệt giữa các thuật toán khác nhau là quá lớn. Ví dụ: nếu tôi đặt N <= 40, sẽ có rất ít sự khác biệt giữa O(KN^2)O(KN^3), tuy nhiên O(2^N)thậm chí sẽ không hoàn thành trong thời gian có thể cộng hưởng.
Colera Su

5
Đây là khá nhiều những gì tôi làm để kiếm sống và tôi có thể nói với bạn nhiều điều này: Đây không phải là cách chúng tôi thiết kế lưới điện!
Stewie Griffin


3
Thử thách xuất sắc, hệ thống tính điểm xuất sắc. Làm tốt!
isaacg

Câu trả lời:


9

Rỉ , điểm = 104

Đây là một triển khai của thuật toán được ghi nhận bởi Grønlund et al. (2017) vào cuối §3.3.1, mặc dù tôi đã phải theo một chuỗi trích dẫn dài và điền vào một số chi tiết còn thiếu. Nó chạy trong O ( N log A [ N - 1]).

Biên dịch với rustc -O. Định dạng đầu vào là Ktrên dòng đầu tiên, theo sau là các mục nhập A, một mục nhập trên mỗi dòng, tất cả trên stdin.

(Lưu ý: Tôi đang gửi này một giờ sau thời hạn tiền thưởng, nhưng tôi hy vọng phiên bản cuối cùng tôi đã gửi trước thời hạn tiền thưởng , chạy trong thời gian O ( N log N log A [ N - 1]), đạt số điểm khoảng 94 .)

use std::cmp::min;
use std::io::{self, BufRead};
use std::iter::{once, Cloned};
use std::num::Wrapping;
use std::ops::Range;
use std::slice;
use std::time::Instant;
use std::u64;

type Cost = u64;
const INF: Cost = u64::MAX;

trait ColsTrait<Col>: Clone {
    type Iter: Iterator<Item = Col>;
    fn len(&self) -> usize;
    fn iter(&self) -> Self::Iter;
    fn slice(&self, range: Range<usize>) -> Self;
}

impl<'a, Col: Clone> ColsTrait<Col> for &'a [Col] {
    type Iter = Cloned<slice::Iter<'a, Col>>;
    fn len(&self) -> usize {
        (*self).len()
    }
    fn iter(&self) -> Self::Iter {
        (*self).iter().cloned()
    }
    fn slice(&self, range: Range<usize>) -> Self {
        unsafe { self.get_unchecked(range) }
    }
}

impl ColsTrait<usize> for Range<usize> {
    type Iter = Range<usize>;
    fn len(&self) -> usize {
        self.end - self.start
    }
    fn iter(&self) -> Range<usize> {
        self.clone()
    }
    fn slice(&self, range: Range<usize>) -> Self {
        Range {
            start: self.start + range.start,
            end: self.start + range.end,
        }
    }
}

fn smawk<Col: Copy, Cols: ColsTrait<Col>, Key: Ord, F: Copy + Fn(usize, Col) -> Key>(
    n: usize,
    shift: u32,
    cols: Cols,
    f: F,
) -> Vec<usize> {
    if n == 0 {
        Vec::new()
    } else if cols.len() > n {
        let mut s = Vec::with_capacity(n);
        let mut sk = Vec::with_capacity(n);
        for (jk, j) in cols.iter().enumerate() {
            while match s.last() {
                Some(&l) => f(!(!(s.len() - 1) << shift), j) <= f(!(!(s.len() - 1) << shift), l),
                None => false,
            } {
                s.pop();
                sk.pop();
            }
            if s.len() < n {
                s.push(j);
                sk.push(jk);
            }
        }
        smawk1(
            n,
            shift,
            cols,
            f,
            smawk(n / 2, shift + 1, &s[..], f)
                .into_iter()
                .map(|h| unsafe { *sk.get_unchecked(h) }),
        )
    } else {
        smawk1(
            n,
            shift,
            cols.clone(),
            f,
            smawk(n / 2, shift + 1, cols, f).into_iter(),
        )
    }
}

fn smawk1<
    Col: Copy,
    Cols: ColsTrait<Col>,
    Key: Ord,
    F: Fn(usize, Col) -> Key,
    Iter: Iterator<Item = usize>,
>(
    n: usize,
    shift: u32,
    cols: Cols,
    f: F,
    iter: Iter,
) -> Vec<usize> {
    let mut out = Vec::with_capacity(n);
    let mut range = 0..0;
    for (i, k) in iter.enumerate() {
        range.end = k + 1;
        out.push(
            range
                .clone()
                .zip(cols.slice(range.clone()).iter())
                .min_by_key(|&(_, col)| f(!(!(2 * i) << shift), col))
                .unwrap()
                .0,
        );
        out.push(k);
        range.start = k;
    }
    if n % 2 == 1 {
        range.end = cols.len();
        out.push(
            range
                .clone()
                .zip(cols.slice(range.clone()).iter())
                .min_by_key(|&(_, col)| f(!(!(n - 1) << shift), col))
                .unwrap()
                .0,
        );
    }
    out
}

fn solve(k: usize, a: &[Cost]) -> Cost {
    if k >= a.len() {
        return 0;
    }
    let sa = once(Wrapping(0))
        .chain(a.iter().scan(Wrapping(0), |s, &x| {
            *s += Wrapping(x);
            Some(*s)
        }))
        .collect::<Vec<_>>();
    let c = |i: usize, j: usize| {
        let h = (i - j) / 2;
        unsafe {
            (sa.get_unchecked(i) - sa.get_unchecked(i - h) - sa.get_unchecked(j + h)
                + sa.get_unchecked(j))
                .0
        }
    };
    let cost1 = c(a.len(), 0);
    if k == 1 {
        return cost1;
    }
    let cost2 = (1..a.len()).map(|j| c(j, 0) + c(a.len(), j)).min().unwrap();
    let mut low = 0;
    let mut high = cost1 - cost2;
    let mut ret = INF;
    while low <= high {
        let penalty = low + (high - low) / 2;
        let mut out = vec![(INF, 0); a.len() + 1];
        out[0] = (0, 0);
        let mut begin = 0;
        let mut chunk = 1;
        loop {
            let r = min(a.len() + 1 - begin, 2 * chunk);
            let edge = begin + chunk;
            let (out0, out1) = out.split_at_mut(edge);
            let f = |i: usize, j: usize| {
                let h = (edge + i - j) / 2;
                let &(cost, count) = unsafe { out0.get_unchecked(j) };
                (
                    cost.saturating_add(
                        unsafe {
                            sa.get_unchecked(edge + i) - sa.get_unchecked(edge + i - h)
                                - sa.get_unchecked(j + h)
                                + sa.get_unchecked(j)
                        }.0 + penalty,
                    ),
                    count + 1,
                )
            };
            for ((i, j), o) in smawk(r - chunk, 0, begin..edge, &f)
                .into_iter()
                .enumerate()
                .zip(out1.iter_mut())
            {
                *o = min(f(i, begin + j), *o);
            }
            let x = unsafe { out1.get_unchecked(r - 1 - chunk) };
            if let Some(j) = (edge..begin + r - 1).find(|&j| &f(r - 1 - chunk, j) <= x) {
                begin = j;
                chunk = 1;
            } else if r == a.len() + 1 - begin {
                break;
            } else {
                chunk *= 2;
            }
        }
        let &(cost, count) = unsafe { out.get_unchecked(a.len()) };
        if count > k {
            low = penalty + 1;
        } else {
            ret = cost.wrapping_sub(k as Cost * penalty);
            if count == k {
                return ret;
            }
            high = penalty - 1;
        }
    }
    ret
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();
    let k = lines.next().unwrap().unwrap().parse().unwrap();
    let a = lines
        .map(|s| s.unwrap().parse().unwrap())
        .collect::<Vec<_>>();
    let start = Instant::now();
    let cost = solve(k, &a);
    let time = start.elapsed();
    println!(
        "cost: {}\ntime: {}.{:09} sec",
        cost,
        time.as_secs(),
        time.subsec_nanos()
    );
}

Hãy thử trực tuyến!

Rỉ , điểm trước = 73

Biên dịch với rustc -O. Định dạng đầu vào là Ktrên dòng đầu tiên, theo sau là các mục nhập A, một mục nhập trên mỗi dòng, tất cả trên stdin.

use std::io::{self, BufRead};
use std::iter::once;
use std::num::Wrapping;
use std::time::Instant;
use std::u64;

type Cost = u64;
const INF: Cost = u64::MAX;

fn smawk<Col: Clone, Key: Ord, F: Clone + Fn(usize, &Col) -> Key>(
    n: usize,
    shift: u32,
    cols: &[Col],
    f: F,
) -> Vec<usize> {
    if n == 0 {
        Vec::new()
    } else if cols.len() > n {
        let mut s = Vec::with_capacity(n);
        let mut sk = Vec::with_capacity(n);
        for (jk, j) in cols.iter().enumerate() {
            while match s.last() {
                Some(l) => f(!(!(s.len() - 1) << shift), j) <= f(!(!(s.len() - 1) << shift), l),
                None => false,
            } {
                s.pop();
                sk.pop();
            }
            if s.len() < n {
                s.push(j.clone());
                sk.push(jk);
            }
        }
        smawk1(
            n,
            shift,
            cols,
            f.clone(),
            smawk(n / 2, shift + 1, &s, f)
                .into_iter()
                .map(|h| unsafe { *sk.get_unchecked(h) }),
        )
    } else {
        smawk1(
            n,
            shift,
            cols,
            f.clone(),
            smawk(n / 2, shift + 1, &cols, f).into_iter(),
        )
    }
}

fn smawk1<Col: Clone, Key: Ord, F: Clone + Fn(usize, &Col) -> Key, Iter: Iterator<Item = usize>>(
    n: usize,
    shift: u32,
    cols: &[Col],
    f: F,
    iter: Iter,
) -> Vec<usize> {
    let mut out = Vec::with_capacity(n);
    let mut range = 0..0;
    for (i, k) in iter.enumerate() {
        range.end = k + 1;
        out.push(
            range
                .clone()
                .zip(unsafe { cols.get_unchecked(range.clone()) })
                .min_by_key(|&(_, col)| f(!(!(2 * i) << shift), col))
                .unwrap()
                .0,
        );
        out.push(k);
        range.start = k;
    }
    if n % 2 == 1 {
        range.end = cols.len();
        out.push(
            range
                .clone()
                .zip(unsafe { cols.get_unchecked(range.clone()) })
                .min_by_key(|&(_, col)| f(!(!(n - 1) << shift), col))
                .unwrap()
                .0,
        );
    }
    out
}

fn solve(k: usize, a: &[Cost]) -> Cost {
    let mut cost = vec![INF; a.len() + 1 - k];
    let sa = once(Wrapping(0))
        .chain(a.iter().scan(Wrapping(0), |s, &x| {
            *s += Wrapping(x);
            Some(*s)
        }))
        .collect::<Vec<_>>();
    cost[0] = 0;
    let cols = (0..a.len() + 1 - k).collect::<Vec<_>>();
    for m in 0..k {
        cost = {
            let f = |i: usize, &j: &usize| {
                if i + 1 >= j {
                    let h = (i + 1 - j) / 2;
                    unsafe {
                        cost.get_unchecked(j).saturating_add(
                            (sa.get_unchecked(i + m + 1) - sa.get_unchecked(i + m + 1 - h)
                                - sa.get_unchecked(j + m + h)
                                + sa.get_unchecked(j + m))
                                .0,
                        )
                    }
                } else {
                    INF
                }
            };
            smawk(a.len() + 1 - k, 0, &cols, &f)
                .into_iter()
                .enumerate()
                .map(|(i, j)| f(i, &j))
                .collect()
        };
    }
    cost[a.len() - k]
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();
    let k = lines.next().unwrap().unwrap().parse().unwrap();
    let a = lines
        .map(|s| s.unwrap().parse().unwrap())
        .collect::<Vec<_>>();
    let start = Instant::now();
    let cost = solve(k, &a);
    let time = start.elapsed();
    println!(
        "cost: {}\ntime: {}.{:09} sec",
        cost,
        time.as_secs(),
        time.subsec_nanos()
    );
}

Hãy thử trực tuyến!


Bạn đã có một số điểm trước 61, nhưng đó là vì tràn u32. Có lẽ bạn có thể thay đổi thành loại số nguyên 64 bit?
Colera Su

@ColeraSu Có tốt hơn không nếu tôi đổi type Cost = u32sang type Cost = u64?
Anders Kaseorg

1
Wow, tôi chưa bao giờ nghĩ về thuật toán SMAWK. Làm tốt lắm, bạn có 73.
Colera Su

2
@ngn Bạn có gì chống lại Rust? :-(
Anders Kaseorg

1
Chúc mừng bạn đã giành được tiền thưởng đầu tiên!
Οurous

5

C, điểm = 56

nội dung của a.c:

typedef void V;typedef char C;typedef long L;typedef unsigned long U;
#define R return
#define W while
#define S static
#include<sys/syscall.h>
#define h1(f,x    )({L r;asm volatile("syscall":"=a"(r):"0"(SYS_##f),"D"(x)              :"cc","rcx","r11","memory");r;})
#define h3(f,x,y,z)({L r;asm volatile("syscall":"=a"(r):"0"(SYS_##f),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
#define read(a...) h3(read ,a)
#define write(a...)h3(write,a)
#define exit(a...) h1(exit ,a)
S V P(U x){C s[32],*p=s+32;*--p='\n';do{*--p='0'+x%10;x/=10;}W(x);write(1,p,s+32-p);}
S V mc(V*x,V*y,L n){C*p=x,*q=y;for(L i=0;i<n;i++)p[i]=q[i];}
#define min(x,y)({typeof(x)_x=(x),_y=(y);_x+(_y-_x)*(_y<_x);})
#define t(x,i,j)x[(i)*(n+n-(i)+1)/2+(j)] //triangle indexing
#define x(i,j)t(x,i,j)
#define y(i,j)t(y,i,j)
#define z(i,j)t(z,i,j)
#define N 4096 //max
L n;U ka[N+1],c[N],x[N*(N+1)/2],y[N*(N+1)/2],z[N*(N+1)/2];
V _start(){
 C s[1<<20];L r=0;U v=0;
 W(0<(r=read(0,s,sizeof(s))))for(L i=0;i<r;i++)if('0'<=s[i]&&s[i]<='9'){v=s[i]-'0'+10*v;}else{ka[n++]=v;v=0;}
 n--;U k=*ka,*a=ka+1;
 for(L i=n-1;i>=0;i--)for(L j=i-1;j>=0;j--)x(j,i)=x(j+1,i)-a[j]+a[i];
 for(L i=0;i<n;i++)for(L j=i+1;j<n;j++)y(i,j)=y(i,j-1)+a[j]-a[i];
 for(L i=n-1;i>=0;i--)for(L j=i+1;j<n;j++){
  U v=~0ul,*p=&x(i,i),*q=&y(i,j);for(L l=i;l<j;l++){v=min(v,*p+++*q);q+=n-l;} //min(v,x(i,l)+y(l,j));
  z(i,j)=v;}
 mc(c,z,8*n);
 for(L m=1;m<k;m++)for(L j=n-1;j>=m;j--){
  U v=~0ul,*p=&z(j,j);for(L i=j-1;i>=m-1;i--){v=min(v,c[i]+*p);p-=n-i;} //min(v,c[i]+z(i+1,j))
  c[j]=v;}
 P(c[n-1]);exit(0);}

shell script để biên dịch và kiểm tra như trên:

#!/bin/bash -e
clang -O3 -nostdlib -ffreestanding -fno-unwind-tables -fno-unroll-loops -fomit-frame-pointer -oa a.c
strip -R.comment -R'.note*' a;stat -c'size:%s' a
t(){ r="$(echo "$1"|./a)";if [ "$r" != "$2" ];then echo "in:$1, expected:$2, actual:$r";fi;} #func tests
t '1 0 2 4 6 8' 12
t '3 0 1 10 11 20 21 22 30 32' 23
t '5 0 1 3 6 8 11 14' 3
t '6 0 1 3 6 8 14 15 18 29 30 38 41 45 46 49 58 66 72 83 84' 49
t '2 0 7 9' 2
for n in 1176 1351 1552 1782 2048;do #perf test
 echo "n:$n";a=0 inp="$((2*n/3))" RANDOM=1;for i in `seq $n`;do inp="$inp $a";a=$((a+=RANDOM%1000));done
 ulimit -t10 -v1048576;time ./a<<<"$inp"
done

n = 776 mất 6,2 giây, n = 891 mất 12 giây

n = 1176 mất 5,9 giây, n = 1351 mất hơn 10 giây

n = 1351 mất 8,7 giây, n = 1552 mất hơn 10 giây (với k = 2 * n / 3) trên tôi Intel(R) Core(TM) i3-2375M CPU @ 1.50GHz


2
Tôi cho rằng đây không phải là golf-code?
dùng202729

@ user202729 Đó là cách tôi thường viết mã C - kiểu incunabulum .
ngn

@ngn Tôi giả sử bạn cũng bình thường không sử dụng bất kỳ loại cú pháp tô sáng nào?
Jonathan Frech

@JonathanFrech Tôi làm, thực sự. Tôi đã tùy chỉnh của tôi syntax/c.vim.
ngn

2
@cole Đây chỉ là C thông thường, chỉ đậm đặc hơn. Nếu bạn quen thuộc với ngôn ngữ, bạn sẽ có thể đọc nó mà không gặp nhiều khó khăn, mặc dù chậm hơn nhiều lần, vì một dòng ở đây chứa thông tin hầu hết các lập trình viên C sẽ trải đều trên 5-10 dòng (thật lãng phí!). Tôi đã viết bình luận chỉ cho các bit khó nhất.
ngn

3

C ++, điểm = 53

Các giải pháp tôi đã nói trong bình luận. O(n²×k). (bây giờ tôi đã xóa nó vì nó không còn cần thiết nữa) Có lẽ có thể rút gọn thànhO(n×k) .

Đầu vào khá linh hoạt, trên dòng đầu tiên, số đầu tiên là k, các số khác là các mục của mảng a, nhưng nếu nó gặp bất kỳ dấu ngoặc đơn gần nào thì nó dừng đọc đầu vào. Vì vậy, đầu vào như K = 1, A = [0, 2, 4, 6, 8] : 12được chấp nhận.

// /codegolf/149029/build-an-electrical-grid

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <climits>

bool read(std::istream& str, int& x) {

    char ch;

    do {
        if (str >> x) return true;
        if (str.eof()) return false;
        str.clear(); // otherwise it's probably int parse error
    } while (str >> ch && ch != ']' && ch != ')' && ch != '}');
    // ignore 1 character, but treat any close parentheses as end of input

    // cannot read anything now
    return false;
}

int main() {
    int k; std::vector<int> a;

    //{ Read input
    std::string st; std::getline(std::cin, st);
    std::stringstream sst (st);

    read(sst, k);

    int x;
    while (read(sst, x)) a.push_back(x);
    //}

    std::vector<std::vector<int>> dp (a.size(), std::vector<int>(k));
    // dp[n][k] = min distance you can get for cities [n..a.size()-1]
    // and [k+1] power plants, and city [n] has a power plant.

    // sum_array[x] = sum of coordinates of cities [x..a.size()-1]
    std::vector<int> sum_array (a.size()+1);
    sum_array.back() = 0;
    for (int n = a.size(); n --> 0;)
        sum_array[n] = sum_array[n+1] + a[n];

    for (int n = a.size(); n --> 0;) {
        for (int k1 = k; k1 --> 0;) {
            if (k1 == 0) {
                int nWire = a.size() - 1 - n;
                dp[n][k1] = sum_array[n+1] - nWire * a[n];
            } else {
            // unindent because my screen width is limited

dp[n][k1] = INT_MAX / 2; // avoid stupid overflow error (in case of -ftrapv)

// let [n1] be the next position for a power plant
int first_connect_right = n; // < lengthy variable name kills screen width
// ^ lengthy comment kills screen width

for (int n1 = n + 1; n1 < (int)a.size(); ++n1) {

    while (a[first_connect_right]-a[n] < a[n1]-a[first_connect_right]) ++first_connect_right;

    int nRightWire = n1 - first_connect_right, nLeftWire = first_connect_right - 1 - n;
    dp[n][k1] = std::min(dp[n][k1],
        a[n1]*nRightWire-(sum_array[first_connect_right]-sum_array[n1]) +
        (sum_array[n+1]-sum_array[first_connect_right])-a[n]*nLeftWire +
        dp[n1][k1-1]
    );

}

            }

        }
    }

    int ans = INT_MAX;
    for (int n = a.size()+1-k; n --> 0;) {
        ans = std::min(ans, dp[n].back() + a[n]*n-sum_array[0]+sum_array[n]);
    }

    std::cout << ans << '\n';

    return 0;
}

Hãy thử trực tuyến!

Tạo các trường hợp thử nghiệm ngẫu nhiên. (đầu vào Nvà tùy chọn phạm vi thành phố, 1000×Ntheo mặc định)


Nếu nó có thể giải quyết một số trường hợp thử nghiệm lớn hơn, tôi sẽ thay đổi ints cần thiết thành int64_ts.
dùng202729

dp [runned_n, runned_k] = min {dp [runned_n-x, runned_k] + f [x, n]}, vì vậy lập trình động trực tiếp là O (n ^ 2 * k). Có lẽ cần phải thay đổi hoàn toàn cách để giảm sự phức tạp?
l4m2

@ l4m2 Đừng làm hỏng thuật toán! (tốt, tiền thưởng chưa hết hạn)
user202729

Xin lỗi, nhưng tôi không biết "spoil" của bạn có nghĩa là "vứt đi" hay "ăn cắp" hay cả hai. Có thể tìm thấy cả hai ý nghĩa. Tôi không biết từ này lắm. (Tôi cũng nghĩ tiền thưởng có nghĩa là bị ràng buộc)
l4m2

2
Trình tạo thử nghiệm ngẫu nhiên không thực thi A [0] = 0 giống như câu hỏi chỉ định.
Anders Kaseorg

2

C #, điểm = 23

Tôi chắc chắn rằng điều này sẽ không chiến thắng thử thách này, tôi chỉ muốn đăng một câu trả lời đầu tiên (và rất cơ bản) để khuyến khích người khác đăng thuật toán của họ và cải thiện tôi. Mã này phải được biên dịch như một dự án giao diện điều khiển sử dụng gói Combinatorics từ NuGet. Phương thức chính chứa một số lệnh gọi đến Buildphương thức để kiểm tra các trường hợp được đề xuất.

using Combinatorics.Collections;
using System;

namespace ElectricalGrid
{
    class Program
    {
        static void Main(string[] args)
        {
            if (Build(1, new long[] { 0, 2, 4, 6, 8 }) == 12)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(3, new long[] { 0, 1, 10, 11, 20, 21, 22, 30, 32 }) == 23)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(5, new long[] { 0, 1, 3, 6, 8, 11, 14 }) == 3)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");
            if (Build(6, new long[] { 0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84 }) == 49)
                Console.WriteLine("OK");
            else
                Console.WriteLine("ERROR");

            Console.ReadKey();
        }

        static long Build(int k, long[] a)
        {
            var combs = new Combinations<long>(a, k);
            var totalDist = long.MaxValue;
            foreach (var c in combs)
            {
                long tempDist = 0;
                foreach (var i in a)
                {
                    var dist = long.MaxValue;
                    foreach (var e in c)
                    {
                        var t = Math.Abs(i - e);
                        if (t < dist) dist = t;
                    }
                    tempDist += dist;
                }
                if (tempDist < totalDist) totalDist = tempDist;
            }
            return totalDist;
        }
    }
}

Giải thích thực sự đơn giản: đối với mỗi sự kết hợp ccủa kcác yếu tố từ a, hãy tính tổng khoảng cách từ mỗi yếu tố ađến yếu tố gần nhất trongc và trả về kết hợp có tổng khoảng cách nhỏ nhất.

Phiên bản một lớp của Buildphương thức (có thể chậm hơn phiên bản gốc, được mở rộng; điều này cần thêm một tham chiếu đến System.Linq):

static long Build(int k, long[] a)
{
    return new Combinations<long>(a, k).Min(c => a.Sum(i => c.Min(e => Math.Abs(i - e))));
}

2

C ++, điểm = 48

#include <stdio.h>
#include <queue>
#include <algorithm>
typedef long long ull;
typedef unsigned int uint;
uint A[1<<20];
ull S[1<<20];

double ky = 1;
struct point {
    ull dist;
    int n;
    inline point() {}
    inline point(ull dist, int n): dist(dist), n(n) {}
    inline double res() const{
        return dist + n * ky;
    }
    inline int operator<(const point& other) const {
        return res() < other.res();
    }
} V[1<<20];
inline ull f(int L, int R) {
    int m = L+R+1 >> 1;
    return (S[R]-S[m]) - A[m]*(R-m) +
           A[m]*(m-L) - (S[m]-S[L]);
}
int main() {
    int N, K, i, j, p;
    scanf ("%d%d", &N, &K);
    ull s = 0;
    for (i=1; i<=N; i++) {
        scanf ("%u", A+i);
        S[i] = s += A[i];
    }
    double kyL = 0, kyH = 1e99;
    point cL, cR;
    for (int step=0; step++<50; ky = std::min(ky*2, (kyL+kyH)*.5)) {
        for (i=1; i<=N; i++) {
            point tmp(f(0,i), 1);
            for (j=1; j<i; j++) {
            //printf("ky=%f [%d]=%d %I64d %f\n", ky, i, tmp.n, tmp.dist, tmp.res());
                point cmp = V[j];
                cmp.dist += f(j, i);
                cmp.n ++;
                if (cmp<tmp) tmp=cmp;
            }
            //printf("ky=%f [%d]=%d %I64d %f\n", ky, i, tmp.n, tmp.dist, tmp.res());
            V[i] = tmp;
        }
        if (V[N].n == K) {
_:          return! printf("%I64d", V[N].dist);
        }
        if (V[N].n > K) {
            kyL = ky;
            cL = V[N];
        } else {
            kyH = ky;
            cR = V[N];
        }
        //printf("ky=%f %d %I64d %f\n", ky, V[N].n, V[N].dist, V[N].res());
        //getch();
    }
    V[N].dist = (double)cL.dist / (cR.n-cL.n) * (K-cL.n) +
                (double)cR.dist / (cL.n-cR.n) * (K-cR.n) + .5;
    printf("%I64d", V[N].dist);
}

Đầu vào sử dụng: NKA [1] A [2] ... A [N]


2
Nếu bạn tăng giới hạn steplên 70, thì điểm số trước của bạn là 60.
Colera Su

2

Ruby , điểm = 23

->a,l{d=l.map{|x|l.map{|y|(x-y).abs}};[*0...l.size].combination(a).map{|r|r.map{|w|d[w]}.transpose.sum{|r|r.min}}.min}

Hãy thử trực tuyến!

Tôi không nghĩ nó sẽ chiến thắng, nhưng tôi muốn thử.


2

JavaScript (ES6) (Node.js) , điểm = 10

Thuật toán mới, sẽ giải thích nếu nó thực sự hoạt động lần này.

const {performance} = require('perf_hooks');

class Connection{
    constructor(left,index,length,right){
        if(typeof right === 'undefined'){
            this._distance = 0;
        } else {
            this._distance = typeof left === 'undefined' ? 0 :
                    Math.abs(right - left);
        }
        var half = Math.floor(length/2);
        if(length % 2 < 1){
            this._magnitude = half - Math.abs(index - half + 1);
        } else {
            var temp = index - half;
            this._magnitude = half - Math.abs(temp >= 0 ?temp:temp + 1);
        }
        this._value = this.distance * this.magnitude;
    }

    get distance(){return this._distance;};
    get magnitude(){return this._magnitude;};
    set magnitude(value){
        this._magnitude = value;
        this._value = this.distance * this.magnitude;
    };
    valueOf(){return this._value};
}

class Group{
	constructor(...connections){
        this._connections = connections;
		
		this._max = Math.max(...connections); //uses the ValueOf to get the highest Distance to the Left
	}
	get connections(){return this._connections;};
	get max(){return this._max;};
    cutLeft(index){

            for(let i=1,j=index-1;;i++){
                
                if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
                    break;
                }
                this.connections[j].magnitude = i;
                j--;
            }

    }

    cutRight(index){

            for(let i=0,j=index;;i++){
                
                if(typeof this.connections[j] === 'undefined' || this.connections[j].magnitude <= i){
                    break;
                }
                this.connections[j].magnitude = i;
                j++;
            }

    }

    static of(...connections){
        return new Group(...connections.map((c,i)=>new Connection(c.distance,i,connections.length)));
    }

	split(){
        var index = this.connections.findIndex(c=>c.valueOf() == this.max);
        if(index < 0){
            return;
        }
        var length = this.connections.length;
        var magnitude = this.connections[index].magnitude;

        this.cutLeft(index);
        this.cutRight(index);
        this._max = Math.max(...this.connections);
	}

    center(){
        if(typeof this._center === 'undefined'){
            this._center = this.connections.reduce((a,b)=>a==0?b.valueOf():a.valueOf()+b.valueOf(),0);
        }
        return this._center;
    }

    valueOf(){return this._max;};
    toString(){
        var index = this.connections.findIndex(c=>c.valueOf() == this.max);
        var value = this.connections[index].magnitude;
        var ret = '';
        for(let i = 0;i<value;i++){
            ret += this.connections.map(c=>{return (i<c.magnitude)?c.distance:' ';}).reduce((a,b)=>a==''?b:a+'-'+b,'') + '\n';
        }
        return ret;
    };
}

function crunch(plants, cities){
	var found = [];
    var size = cities.length;
    cities = cities.map((city,i,arr)=> new Connection(city,i,size,arr[i+1])).slice(0,cities.length-1);
    var group = new Group(...cities);
    for(;plants>1;plants--){
    group.split();
    }
    console.log(`Wire Length Needed: ${group.center()}`);
}

function biggestGroup(groups){
	return groups.find(g => g[g.length-1].orig - g[0].orig);
}

function* range (start, end, limit) {
    while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
        yield start
        start += 1 + Math.floor(Math.random()*100);
    }
}

function* cities (score){
	let n = Math.floor(Math.pow(2,score/5));
	var start = 0;
	while (n-- > 0 && start <= (1000 * n)) {
		yield start;
        start += 1 + Math.floor(Math.random()*100);
    }
}


if(typeof process.argv[3] === 'undefined'){
    crunch(1,[0, 2, 4, 6, 8]);
    console.log("Correct Answer: 12");
    crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
    console.log("Correct Answer: 23");
    crunch(5,[0, 1, 3, 6, 8, 11, 14]);
    console.log("Correct Answer: 3");
    crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
    console.log("Correct Answer: 49");
    crunch(2, [0, 21, 31, 45, 49, 54]);
    console.log("Correct Answer: 40");
    crunch(2, [0, 4, 7, 9, 10]);
    console.log("Correct Answer: 7");
    crunch(2, [0, 1, 3, 4, 9]);
    console.log("Correct Answer: 6");
    
    var max = 0;
    var min = Number.POSITIVE_INFINITY;
    var avg = [];
    
    var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];

    for(j = 0; j<10; j++){
        var arr = []; for(let i of cities(score)) arr.push(i);
        var plants = Math.floor(1 + Math.random() * arr.length);
        console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
        // console.log(`City Array: [${arr}]`);
        var t0 = performance.now();
        crunch(plants,arr);
        var t1 = performance.now();
        time = (t1-t0)/1000;
        console.log(`Time Taken = ${time} seconds`);
        avg.push(time);
        max = Math.max(time,max);
        min = Math.min(time,min);
    }
    console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
    var plants = process.argv[2];
    var arr = process.argv.slice(3);
    console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
    var t0 = performance.now();
    crunch(plants,arr);
    var t1 = performance.now();
    time = (t1-t0)/1000;
    console.log(`Time Taken = ${time} seconds`);
}

Hãy thử trực tuyến!

Chạy giống như cách khác.

JavaScript (ES6) (Node.js) , điểm trước = 12

Sơ lược về thuật toán:

Chương trình trước tiên ánh xạ Dữ liệu vào Lớp Thành phố, ánh xạ một vài điểm dữ liệu:

  • thành phố - khoảng cách tuyệt đối của thành phố
  • bên trái - khoảng cách của thành phố gần nhất bên trái
  • bên phải - khoảng cách của thành phố gần nhất bên phải
  • chỉ mục - chỉ số (không dùng nữa) trong mảng thành phố ban đầu

mảng sau đó được ném vào lớp Nhóm, có các mục sau:

  • thành phố - mảng thành phố
  • dist - khoảng cách kéo dài nhóm
  • tối đa - kết nối bên trái lớn nhất trong nhóm
  • chia ()
    • trả về một mảng chứa các nhóm phụ được phân chia dọc theo kết nối lớn nhất được kết nối với thành phố trung tâm trong nhóm
    • nếu có 2 nút trung tâm (một nhóm độ dài chẵn) thì nó chọn từ 3 kết nối đó
    • (* lưu ý *: điều này sẽ loại bỏ bất kỳ nhóm nào có ít hơn hai thành phố)
  • trung tâm()
    • trả về giá trị dây tốt nhất cho nhóm
    • làm việc trên một giải pháp để bỏ qua việc lặp lại qua từng thành phố còn lại cho bước này
    • bây giờ với ánh xạ ít hơn 50%

Bây giờ thuật toán tiến hành phân chia các nhóm miễn là có 2 nhà máy điện trở lên.

Cuối cùng, nó ánh xạ các nhóm đến trung tâm của nó và tổng hợp tất cả chúng lại.

Cách chạy:

Chạy bằng Node.js (v9.2.0 là những gì đã được sử dụng để tạo)

chạy chương trình bằng các trường hợp kiểm tra được tạo cho điểm 70:

node program.js 70

chạy chương trình sử dụng 1 nhà máy điện và thành phố [0,3,5]:

node program.js 1 0 3 5

Mã số:

const {performance} = require('perf_hooks');

class City{
	constructor(city, left, right, i){
		this._city = city;
		this._index = i;
		this._left = typeof left === 'undefined' ? 0 : city - left;
		this._right = typeof right === 'undefined' ? 0 : right - city;
	}

	get city(){return this._city;};
	get index(){return this._index;};
	get left(){return this._left;};
    get right(){return this._right;};
    set left(left){this._left = left};
    set right(right){this._right = right};

	valueOf(){return this._left;};
}

class Group{
	constructor(...cities){
        this._cities = cities;
        // console.log(cities.map(a=>a.city).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log(cities.map(a=>a.left).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log(cities.map(a=>a.right).reduce((a,b)=>a===''?a+(b<10?' '+b:b):a+'-'+(b<10?' '+b:b),""));
        // console.log("+==+==+==+==+==+==+==+==+==+==+==+==")
		this._dist = cities[cities.length-1].city - cities[0].city;
		this._max = Math.max(...cities); //uses the ValueOf to get the highest Distance to the Left
	}

	get dist(){return this._dist;};
	get cities(){return this._cities;};
	get max(){return this._max;};

	split(){
        //var index = this.cities.findIndex(city=>city.left == this.max);
        //this.cities[index].left = 0;
        // console.log(`Slicing-${this.max}-${index}------`)
        var centerIndex = this.cities.length / 2;
        var splitIndex = Math.floor(centerIndex);
        if(centerIndex%1 > 0){
            var center = this.cities[splitIndex];
            if(center.right > center.left){

                splitIndex++;
            }
        } else {
            var right = this.cities[splitIndex];
            var left = this.cities[splitIndex-1];
            if(left.left > Math.max(right.right,right.left)){
               
                splitIndex--;
            } else if(right.right > Math.max(left.left,left.right)){
                
                splitIndex++;
            }
        }
        // console.log(splitIndex);
        this.cities[splitIndex].left = 0;
        this.cities[splitIndex-1].right = 0;
        var leftCities = [...this.cities.slice(0,splitIndex)];
        var rightCities = [...this.cities.slice(splitIndex)];

        // var center = this.cities[]

        if(leftCities.length <= 1){
            if(rightCities.length <= 1){
                return [];
            }
            return [new Group(...rightCities)]
        }
        if(rightCities.length <= 1){
            return [new Group(...leftCities)];
        }
        return [new Group(...leftCities), new Group(...rightCities)];
	}

    center(){
        if(typeof this._center === 'undefined'){
            if(this.cities.length == 1){
                return [0];
            }
            if(this.cities.length == 2){
                return this.cities[1].left;
            }
            var index = Math.floor(this.cities.length/2);
            this._center = this.cities.reduce((a,b)=> {
                // console.log(`${a} + (${b.city} - ${city.city})`);
                return a + Math.abs(b.city - this.cities[index].city);
            },0);
            // console.log(this._center);
        }
        
        return this._center;
    }

	valueOf(){return this._max;};
}

function crunch(plants, cities){
	var found = [];
    var size = cities.length;
    cities = cities.map((city,i,arr)=> new City(city,arr[i-1],arr[i+1],i));
	var groups = [new Group(...cities)];

	// console.log(groups);
    for(;plants>1;plants--){
        var mapped = groups.map(g=>g.center()-g.max);
        var largest = Math.max(...groups);
        // console.log('Largest:',largest)
        // console.log(...mapped);
		var index = groups.findIndex((g,i)=> mapped[i] == g.center() - g.max && g.max == largest);
		// console.log(index);
        groups = index == 0 ? 
            [...groups[index].split(),...groups.slice(index+1)]:
            [...groups.slice(0,index),...groups[index].split(),...groups.slice(index+1)];
    }
    // console.log(`=Cities=${size}================`);
    // console.log(groups);
    size = groups.map(g=>g.cities.length).reduce((a,b)=>a+b,0);
    
    // console.log(`=Cities=${size}================`);
    var wires = groups.map(g=>g.center());
    
    // console.log(...wires);
    // console.log(`=Cities=${size}================`);
    console.log(`Wire Length Needed: ${wires.reduce((a,b)=>a + b,0)}`);
}

function biggestGroup(groups){
	return groups.find(g => g[g.length-1].orig - g[0].orig);
}

function* range (start, end, limit) {
    while (start < end || typeof limit !== 'undefined' && limit-- > 0) {
        yield start
        start += 1 + Math.floor(Math.random()*100);
    }
}

function* cities (score){
	let n = Math.floor(Math.pow(2,score/5));
	var start = 0;
	while (n-- > 0 && start <= (1000 * n)) {
		yield start;
        start += 1 + Math.floor(Math.random()*100);
    }
}

if(typeof process.argv[3] === 'undefined'){
    crunch(1,[0, 2, 4, 6, 8]);
    console.log("Correct Answer: 12");
    crunch(3,[0, 1, 10, 11, 20, 21, 22, 30, 32]);
    console.log("Correct Answer: 23");
    crunch(5,[0, 1, 3, 6, 8, 11, 14]);
    console.log("Correct Answer: 3");
    crunch(6,[0, 1, 3, 6, 8, 14, 15, 18, 29, 30, 38, 41, 45, 46, 49, 58, 66, 72, 83, 84]);
    console.log("Correct Answer: 49");
    crunch(2, [0, 21, 31, 45, 49, 54]);
    console.log("Correct Answer: 40");
    crunch(2, [0, 4, 7, 9, 10]);
    console.log("Correct Answer: 7");
    
    var max = 0;
    var min = Number.POSITIVE_INFINITY;
    var avg = [];
    
    var score = typeof process.argv[2] === 'undefined' ? 60 : process.argv[2];

    for(j = 0; j<10; j++){
        var arr = []; for(let i of cities(score)) arr.push(i);
        var plants = Math.floor(1 + Math.random() * arr.length);
        console.log(`Running: Test:${j} Plants: ${plants}, Cities ${arr.length}, Score: ${score}`);
        var t0 = performance.now();
        crunch(plants,arr);
        var t1 = performance.now();
        time = (t1-t0)/1000;
        console.log(`Time Taken = ${time} seconds`);
        avg.push(time);
        max = Math.max(time,max);
        min = Math.min(time,min);
    }
    console.log(`Bench: ${avg.reduce((a,b)=>a+b,0)/avg.length} Max: ${max} Min: ${min} Total: ${avg.reduce((a,b)=>a+b,0)}`);
} else {
    var plants = process.argv[2];
    var arr = process.argv.slice(3);
    console.log(`Running: Plants: ${plants}, Cities ${arr.length}`);
    var t0 = performance.now();
    crunch(plants,arr);
    var t1 = performance.now();
    time = (t1-t0)/1000;
    console.log(`Time Taken = ${time} seconds`);
}

Hãy thử trực tuyến!

Tôi sẽ dọn sạch mã nhận xét trong vài ngày tới vì tôi vẫn đang làm việc này, chỉ muốn xem liệu điều này có vượt qua nhiều hơn những trường hợp nhỏ không.


Hãy xem xét các testcase K = 2, A = [0, 21, 31, 45, 49, 54]. Câu trả lời đúng là 40, nhưng chương trình của bạn cho ra 51.
Colera Su

Thậm chí đơn giản hơn : K = 2, A = [0, 4, 7, 9, 10]. Đúng: 7, câu trả lời của bạn: 8.
Colera Su

Được rồi Nó sẽ hoạt động ngay bây giờ ... Nó ít nhất hoạt động cho tất cả các trường hợp được cung cấp.
Wilson Johnson Reta 232

Trên thực tế tôi cũng có thể đã bắt nguồn một thuật toán khác hoạt động tốt hơn. Tôi sẽ kiểm tra lý thuyết và đăng nó một chút.
Wilson Johnson Reta 232

Vẫn không hoạt động ... K = 2, A = [0, 1, 3, 4, 9]. Đúng: 6, câu trả lời của bạn: 7.
Colera Su

1

C (không cạnh tranh, điểm trước = 76)

Đây là một nỗ lực để dịch giải pháp Rust thứ hai của @ AndersKaseorg sang C.

typedef void V;typedef char C;typedef long L;
#define R return
#define W while
#define S static
#include<sys/syscall.h>
#define exit(x)     ({L r;asm volatile("syscall":"=a"(r):"0"(SYS_exit ),"D"(x)              :"cc","rcx","r11","memory");r;})
#define read(x,y,z) ({L r;asm volatile("syscall":"=a"(r):"0"(SYS_read ),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
#define write(x,y,z)({L r;asm volatile("syscall":"=a"(r):"0"(SYS_write),"D"(x),"S"(y),"d"(z):"cc","rcx","r11","memory");r;})
S V P(L x){C s[32],*p=s+32;*--p='\n';do{*--p='0'+x%10;x/=10;}W(x);write(1,p,s+32-p);}
#define N 0x100000 //max
#define INF (-1ul>>1)
S L cost[N],nk1,*am; //nk1:n-k+1, am:input's partial sums offset with the current "m" in _start()
S L f(L i,L j){if(i+1>=j&&cost[j]!=INF){L h=(i-j+1)>>1;R cost[j]+am[i+1]-am[j+h]-am[i-h+1]+am[j];}else{R INF;}}
S V smawk(L sh,L*c,L nc,L*r){ //sh:shift,c:cols,r:result
 L n=nk1>>sh;if(!n)R;
 L m=n>>1,u[m];
 if(n<nc){
  L ns=0,s[nc],sk[nc],*skp=sk;
  for(L jk=0;jk<nc;jk++){
   L j=c[jk];W(ns>0&&f(~(~(ns-1)<<sh),j)<=f(~(~(ns-1)<<sh),s[ns-1])){--ns;--skp;}
   if(ns<n){s[ns++]=j;*skp++=jk;}
  }
  smawk(sh+1,s,ns,u);for(L i=0;i<m;i++)u[i]=sk[u[i]];
 }else{
  smawk(sh+1,c,nc,u);
 }
 L l=0,ish=(1<<sh)-1,dsh=1<<(sh+1);
 for(L i=0;i<m;i++){
  L k=u[i],bj=l,bc=f(ish,c[l]);
  for(L j=l+1;j<=k;j++){L h=f(ish,c[j]);if(h<bc){bc=h;bj=j;}}
  *r++=bj;*r++=k;l=k;ish+=dsh;
 }
 if(n&1){
  L nsh=~(~(n-1)<<sh),bj=l,bc=f(nsh,c[l]);
  for(L j=l+1;j<nc;j++){L h=f(nsh,c[j]);if(h<bc){bc=h;bj=j;}}
  *r=bj;
 }
}
S L inp(L*a){
 L n=-1,l,v=0;C b[1<<20];
 W(0<(l=read(0,b,sizeof(b))))for(L i=0;i<l;i++)if('0'<=b[i]&&b[i]<='9'){v=b[i]-'0'+10*v;}else{a[++n]=v;v=0;}
 R n;
}
V _start(){
 S L a[N];L n=inp(a),k=*a,s=0;for(L i=0;i<n;i++){a[i]=s;s+=a[i+1];}a[n]=s;
 *cost=0;for(L i=1,l=n+1-k;i<l;i++)cost[i]=INF;
 S L c[N];L nc=n+1-k;for(L i=0;i<nc;i++)c[i]=i;
 S L r[N];nk1=n-k+1;for(L m=0;m<k;m++){am=a+m;smawk(0,c,nc,r);for(L i=n-k;i>=0;i--)cost[i]=f(i,r[i]);}
 P(cost[n-k]);exit(0);
}

Biên dịch với:

#!/bin/bash -e
clang -O3 -nostdlib -ffreestanding -fno-unwind-tables -fno-unroll-loops -fomit-frame-pointer -oa a.c
strip -R.comment -R'.note*' a

1

Sạch sẽ , điểm = 65

module main
import StdEnv, System.IO

parseArgs :: *World -> ((Int, {#Int}), *World)
parseArgs world
    # (args, world)
        = nextArgs [] world
    # args
        = reverse args
    # (k, a)
        = (hd args, tl args)
    = ((toInt k, {toInt n \\ n <- a}), world)
where
    nextArgs :: [String] *World -> ([String], *World)
    nextArgs args world
        # (arg, world)
            = evalIO getLine world
        | arg == ""
            = (args, world)
        = nextArgs [arg:args] world

minimalWeight :: Int !{#Int} -> Int
minimalWeight k a
    # count
        = size a
    # touches
        = createArray ((count - k + 3) / 2 * k) 0
    = treeWalk k count a [(0, 0, 0, 0)] touches
where
    treeWalk :: Int !Int {#Int} ![(!Int, !Int, Int, Int)] *{Int} -> Int
    treeWalk k verticies a [(weight, vertex, degree, requires) : nodes] touches
        | vertex >= verticies
            = weight
        | requires >= k
            = treeWalk k verticies a nodes touches
        # index
            = degree * k + requires
        | (select touches index) > vertex
            = treeWalk k verticies a nodes touches
        # (next, pivot)
            = (vertex + 1 + degree, verticies + requires)
        # (nodes, touches)
            = (orderedPrepend (weight, next, 0, requires + 1) nodes, update touches index (vertex + 1))
        | pivot >= k + next
            # (weight, vertex)
                = (weight + (select a next) - (select a vertex), vertex + 1)
            # nodes
                = orderedPrepend (weight, next + 1, 0, requires + 1) nodes
            | pivot == k + next
                = treeWalk k verticies a nodes touches
            # weight
                = weight + (select a (next + 1)) - (select a vertex)
            # nodes
                = orderedPrepend (weight, vertex, degree + 1, requires) nodes
            = treeWalk k verticies a nodes touches
        = treeWalk k verticies a nodes touches
    where
        orderedPrepend :: (!Int, Int, Int, Int) ![(!Int, Int, Int, Int)] -> [(Int, Int, Int, Int)]
        orderedPrepend a []
            = [a]
        orderedPrepend a [b : b_]
            # (x, _, _, _)
                = a
            # (y, _, _, _)
                = b
            | y > x
                = [a, b : b_]
            = [b : orderedPrepend a b_]

Start world
    # ((k, a), world)
        = parseArgs world
    = minimalWeight k a

Biên dịch với:
clm -h 1024M -gci 32M -gcf 32 -s 32M -t -nci -ou -fusion -dynamics -IL Platform main

Lấy K, và sau đó từng phần tử của A, làm đối số dòng lệnh.


@ColeraSu Tôi có thể hỏi yếu tố quyết định trong điểm số là gì không? Đúng / Thời gian / Bộ nhớ? Tôi hy vọng đó là thời gian.
urur

Bạn nói đúng, đã đến lúc.
Colera Su
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.