นับอาร์เรย์ที่สร้างชุดพิเศษ


11

คำถามนี้มีการตั้งค่าคล้ายกับFind a array ที่เหมาะกับชุดของผลรวมแม้ว่าจะค่อนข้างแตกต่างกันในเป้าหมาย

พิจารณาอาร์เรย์ของความยาวA nอาร์เรย์มีจำนวนเต็มบวกเท่านั้น A = (1,1,2,2)เช่น ให้เรากำหนดf(A)เป็นชุดของผลรวมของทุกคนที่ไม่ว่างเปล่า subarrays Aต่อเนื่องกันของ ในกรณีf(A) = {1,2,3,4,5,6}นี้ ขั้นตอนในการผลิตf(A) มีดังนี้:

subarrays ของAreA จำนวนเงินของตนมี(1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2) ชุดที่คุณได้รับจากรายการนี้จึงเป็น1,1,2,2,2,3,4,4,5,6{1,2,3,4,5,6}

เราเรียกอาเรย์ที่A ไม่ซ้ำกันถ้าไม่มีอาเรย์อื่นBที่มีความยาวเท่ากันเช่นนั้นf(A) = f(B)ยกเว้นสำหรับอาเรย์ที่Aกลับด้าน เป็นตัวอย่างf((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}แต่ไม่มีความยาวอื่น ๆ3ที่สร้างชุดของผลรวมเดียวกัน

เราจะพิจารณาอาร์เรย์ที่องค์ประกอบที่มีทั้งจำนวนเต็มรับหรือs s+1เช่นถ้าs=1อาร์เรย์เท่านั้นที่จะมีและ12

งาน

งานสำหรับที่กำหนดnและsจะนับจำนวนอาร์เรย์ที่ไม่ซ้ำกันของความยาวนั้น คุณสามารถสรุปได้ว่าsอยู่ระหว่างและ19

คุณไม่ควรนับการย้อนกลับของอาเรย์รวมทั้งอาเรย์เอง

ตัวอย่าง

s = 1n+1คำตอบอยู่เสมอ

s = 2คำตอบที่นับจากn = 1ขึ้นคือ:

2,3,6,10,20,32,52,86

s = 8คำตอบที่นับจากn = 1ขึ้นคือ:

2,3,6,10,20,36,68,130

คะแนน

สำหรับรับnรหัสของคุณควรเอาท์พุทคำตอบสำหรับทุกค่าของsจากไป1 9คะแนนของคุณคือมูลค่าสูงสุดnซึ่งจะเสร็จสมบูรณ์ในหนึ่งนาที

การทดสอบ

ฉันจะต้องเรียกใช้รหัสของคุณบนเครื่องอูบุนตูของฉันดังนั้นโปรดระบุคำแนะนำโดยละเอียดที่สุดเท่าที่จะทำได้เพื่อรวบรวมและเรียกใช้รหัสของคุณ

ลีดเดอร์บอร์ด

  • n = 24โดย Anders Kaseorg ในRust (34 วินาที)
  • n = 16โดย Ourous in Clean (36 วินาที)
  • n = 14โดย JRowan ในCommon LISP (49 วินาที)

ดังนั้นถ้า s = 8 แล้วอาร์เรย์ของชุดค่าผสมที่เป็นไปได้ทั้งหมดของ 8 และ 9 ไม่มีอะไรอีกแล้ว?
JRowan

@JRowan ไม่คุณไม่นับอาร์เรย์ใด ๆ ที่มีผลรวมของชุดเดียวกันกับอาร์เรย์อื่น
Anush

ส่วนนี้ฉันสับสนเล็กน้อยเกี่ยวกับเราจะพิจารณาเฉพาะอาร์เรย์ที่องค์ประกอบนั้นเป็นจำนวนเต็ม s หรือ s + 1 เช่นถ้า s = 1 อาร์เรย์จะมีเพียง 1 และ 2 ดังนั้นถ้า n คือ 2 และ s คือ 3 อาร์เรย์ที่จะทดสอบคืออะไร
JRowan

แล้ว [3,3] และ im กำลังลบสิ่งที่ตรงกันข้ามของรายการเช่น [3,4] -> [4,3]
JRowan

2
@RosLuP ประการแรกคุณหมายถึงการโพสต์คำถามนั้นในคำถามอื่นและประการที่สอง [3, 5, 4] เป็นเซตย่อย แต่ไม่ได้เป็นหัวข้อย่อย [3, 5, 1, 4]
Anders Kaseorg

คำตอบ:


5

สนิม n ≈ 24

ต้องใช้ Rust ทุกคืนเพื่อreverse_bitsคุณสมบัติที่สะดวก รวบรวมrustc -O unique.rsและทำงานด้วย ./unique 24(เช่น)

#![feature(reverse_bits)]
use std::{collections::HashMap, env, mem, process};

type T = u32;
const BITS: u32 = mem::size_of::<T>() as u32 * 8;

fn main() {
    let args = env::args().collect::<Vec<_>>();
    assert!(args.len() == 2);
    let n: u32 = args[1].parse().unwrap();
    assert!(n > 0);
    assert!(n <= BITS);
    let mut unique = (2..=9).map(|_| HashMap::new()).collect::<Vec<_>>();
    let mut sums = vec![0 as T; n as usize];
    for a in 0 as T..=!0 >> (BITS - n) {
        if a <= a.reverse_bits() >> (BITS - n) {
            for v in &mut sums {
                *v = 0;
            }
            for i in 0..n {
                let mut bit = 1;
                for j in i..n {
                    bit <<= a >> j & 1;
                    sums[(j - i) as usize] |= bit;
                }
            }
            for s in 2..=9 {
                let mut sums_s =
                    vec![0 as T; ((n + (n - 1) * s) / BITS + 1) as usize].into_boxed_slice();
                let mut pos = 0;
                let mut shift = 0;
                let mut lo = 0;
                let mut hi = 0;
                for &v in &sums {
                    lo |= v << shift;
                    if BITS - shift < n {
                        hi |= v >> (BITS - shift);
                    }
                    shift += s;
                    if shift >= BITS {
                        shift -= BITS;
                        sums_s[pos] = lo;
                        pos += 1;
                        lo = hi;
                        hi = 0;
                    }
                }
                if lo != 0 || hi != 0 {
                    sums_s[pos] = lo;
                    pos += 1;
                    if hi != 0 {
                        sums_s[pos] = hi;
                    }
                }
                unique[s as usize - 2]
                    .entry(sums_s)
                    .and_modify(|u| *u = false)
                    .or_insert(true);
            }
        }
    }
    let mut counts = vec![n + 1];
    counts.extend(
        unique
            .iter()
            .map(|m| m.values().map(|&u| u as T).sum::<T>())
            .collect::<Vec<_>>(),
    );
    println!("{:?}", counts);
    process::exit(0); // Avoid running destructors.
}

ขอบคุณมาก จะเสร็จสมบูรณ์เป็นเวลา n = 25 ในประมาณ 90 วินาที แต่ปัญหาหลักคือมันใช้ RAM 70% ของ 8GB ของฉัน
Anush

ทันใดนั้นฉันก็มีความกังวลเกี่ยวกับบางสิ่งบางอย่าง คุณกำลังตรวจสอบว่าอาร์เรย์นั้นมีความเป็นเอกลักษณ์ที่เกี่ยวกับอาร์เรย์ที่เป็นไปได้อื่น ๆ ทั้งหมดหรือเพียงแค่อาร์เรย์ที่มีค่าsและs+1อยู่ในนั้น
Anush

@Anush ใช่ฉันแลกเปลี่ยนการใช้งานหน่วยความจำเพื่อความรวดเร็ว ฉันกำลังนับอาร์เรย์ที่เป็นค่าเฉพาะของอาเรย์อื่น ๆ ที่มีค่าsและs + 1(เนื่องจากคุณบอกว่าเป็นอาเรย์เดียวที่เราจะพิจารณา) ถึงแม้ว่ามันจะไม่ชัดเจนในทันทีว่ามันจะสร้างความแตกต่างหรือไม่
Anders Kaseorg

1
ฉันคิดว่าฉันจะต้องออกไปทำงานในวันพรุ่งนี้ อาร์เรย์ 1,1,2,2 และ 1,1,1,3 ทั้งคู่ให้ผลรวมเป็นจำนวน 1,2,3,4,5,6 อย่างไรก็ตามอดีตไม่ได้มีความโดดเด่นในอาร์เรย์ที่มีเพียง 1 และ 2 ดังนั้นฉันจึงสับสนเล็กน้อยถ้ามันสร้างความแตกต่างในขณะนี้
Anush

2
@Anush มันสร้างความแตกต่างได้: ผลรวมของ [1, 2, 2, 2] นั้นไม่ซ้ำกันระหว่างอาร์เรย์ที่มี 1 และ 2 ของความยาว 4 แต่เท่ากับผลรวมของ [1, 1, 2, 3]
Anders Kaseorg

2

Common Lisp SBCL, N = 14

ฟังก์ชั่นการโทร (goahead ns)

    (defun sub-lists(l m &optional(x 0)(y 0))
  (cond; ((and(= y (length l))(= x (length l)))nil)
        ((= y (length l))m)
        ((= x (length l))(sub-lists l m 0(1+ y)))
    (t (sub-lists l (cons(loop for a from x to (+ x y)

             when (and(nth (+ x y)l)(nth a l)(< (+ x y)(length l)))
                ;   while (nth a l)
             ;while(and(< (+ x y)(length l))(nth a l))
                    collect (nth a l))m) (1+ x)y))
    ))
(defun permutations(size elements)
  (if (zerop size)'(())
 (mapcan (lambda (p)
                    (map 'list (lambda (e)
                           (cons e p))
                         elements))
     (permutations (1- size) elements))))
(defun remove-reverse(l m)
  (cond ((endp l)m)
    ((member (reverse (first l))(rest l) :test #'equal)(remove-reverse (rest l)m))
    (t (remove-reverse (rest l)(cons (first l)m)))))
(defun main(n s)
  (let((l (remove-reverse (permutations n `(,s ,(1+ s)))nil)))

  (loop for x in l
     for j = (remove 'nil (sub-lists x nil))
       collect(sort (make-set(loop for y in j
        collect (apply '+ y))nil)#'<)
     )
  ))
(defun remove-dups(l m n)
  (cond ((endp l)n)
        ((member (first l) (rest l) :test #'equal)(remove-dups(rest l)(cons (first l) m) n))
    ((member (first l) m :test #'equal)(remove-dups(rest l)m n))
    (t(remove-dups (rest l) m (cons (first l) n))))

  )
(defun goahead(n s)
  (loop for a from 1 to s
  collect(length (remove-dups(main n a)nil nil))))
(defun make-set (L m)
  "Returns a set from a list. Duplicate elements are removed."
  (cond ((endp L) m)
    ((member (first L) (rest L)) (make-set (rest L)m))
    ( t (make-set (rest L)(cons (first l)m)))))

นี่คือเวลาทำงาน

CL-USER> (time (goahead 14 9))
Evaluation took:
  34.342 seconds of real time
  34.295000 seconds of total run time (34.103012 user, 0.191988 system)
  [ Run times consist of 0.263 seconds GC time, and 34.032 seconds non-GC time. ]
  99.86% CPU
  103,024,254,028 processor cycles
  1,473,099,744 bytes consed

(15 1047 4893 6864 7270 7324 7328 7328 7328)
CL-USER> (time (goahead 15 9))
Evaluation took:
  138.639 seconds of real time
  138.511089 seconds of total run time (137.923824 user, 0.587265 system)
  [ Run times consist of 0.630 seconds GC time, and 137.882 seconds non-GC time. ]
  99.91% CPU
  415,915,271,830 processor cycles
  3,453,394,576 bytes consed

(16 1502 8848 13336 14418 14578 14594 14594 14594)

ฉันจะเรียกใช้สิ่งนี้ได้อย่างไร ฉันจะคัดลอกรหัสของคุณไปยังไฟล์และโทรจากsbclอย่างใด?
Anush

1
ฉันใช้ emacs และน้ำเมือก แต่คุณสามารถใส่มันลงในไฟล์บอกว่า test.lisp และใน sbcl promp ที่การเรียกใช้ไดเรกทอรีของคุณ (โหลด "test.lisp") แล้วเรียกฟังก์ชั่นว่าฉันมีที่ด้านล่างอย่างไร
JRowan

2

สะอาด

ไม่ใช่วิธีที่มีประสิทธิภาพมากที่สุด แต่ฉันสนใจที่จะดูว่าตัวกรองค่าไร้เดียงสานั้นดีเพียงใด

ที่กล่าวว่ายังมีการปรับปรุงเล็กน้อยที่จะทำโดยใช้วิธีนี้

module main
import StdEnv, Data.List, System.CommandLine

f l = sort (nub [sum t \\ i <- inits l, t <- tails i])

Start w
	# ([_:args], w) = getCommandLine w
	= case map toInt args of
		[n] = map (flip countUniques n) [1..9]
		_ = abort "Wrong number of arguments!"

countUniques 1 n = inc n
countUniques s n = length uniques
where
	lists = [[s + ((i >> p) bitand 1) \\ p <- [0..dec n]] \\ i <- [0..2^n-1]]
	pairs = sortBy (\(a,_) (b,_) = a < b) (zip (map f lists, lists))
	groups = map (snd o unzip) (groupBy (\(a,_) (b,_) = a == b) pairs)
	uniques = filter (\section = case section of [a, b] = a == reverse b; [_] = True; _ = False) groups

สถานที่ในไฟล์ชื่อหรือเปลี่ยนแปลงบรรทัดด้านบนเพื่อmain.iclmodule <your_file_name_here>

clm -h 1500m -s 50m -fusion -t -IL Dynamics -IL StdEnv -IL Platform mainคอมไพล์ด้วย

คุณจะได้รับรุ่น TIO (และตัวเอง) ใช้จากการเชื่อมโยงในหัวข้อหรือหนึ่งล่าสุดจากที่นี่


ฉันไม่คิดว่ารหัสนี้ให้ผลลัพธ์ที่ถูกต้อง ฉันลองด้วย s = 8 และให้ [9,86,126,130,130,130,130,130,130]
Anush

@ ตอบกลับอืมฉันรู้ว่าฉันทดสอบแล้ว ฉันจะดูว่าฉันเปลี่ยนอะไรระหว่างนั้นและโพสต์หนึ่งให้ฉันสองสามชั่วโมงและฉันสามารถทำได้ในช่วงพักของฉัน
Οurous

@Anush ทำไมคุณให้s? ในคำถามที่คุณระบุว่า " สำหรับ n ที่ระบุรหัสของคุณควรส่งคำตอบสำหรับค่าทั้งหมดของ s จาก 1 ถึง 9"
Οurous

1
ฉันคิดว่านั่นคือสิ่งที่คุณเรียกว่าสมองหยุดนิ่งในส่วนของฉัน :) ฉันจะใส่รหัสของคุณตอนนี้
Anush
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.