अवधि की गिनती गिनें


11

periodएक स्ट्रिंग की कम से कम गैर शून्य पारी ताकि स्वयं स्ट्रिंग से मेल खाता है, किसी भी हिस्से कि अधिकता अनदेखी है। उदाहरण के लिए, abcabcabअवधि है 3। कन्वेंशन से हम कहते हैं कि अगर ऐसी कोई बदलाव नहीं होता है, तो एक स्ट्रिंग की लंबाई के बराबर अवधि होती है। तो की अवधि abcdeहै 5और की अवधि aहै 1

अधिक औपचारिक शब्दों में, एक स्ट्रिंग की अवधि Sन्यूनतम है i > 0ताकि S[1,n-i] == S[i+1,n](से अनुक्रमण 1) हो।

दो लंबाई की शक्ति के दिए गए स्ट्रिंग एस के लिए, हम दो लंबाई की शक्ति के सभी उपसर्गों की अवधि की गणना करेंगे। उदाहरण के लिए, विचार करें S = abcabcab। हम जिन काल की गणना करेंगे वे हैं:

'a', 1
'ab', 2
'abca', 3
'abcabcab', 3

हम वास्तव में सिर्फ पीरियड्स के एरे को आउटपुट करेंगे, जो कि है [1, 2, 3, 3]

दो की दी गई सकारात्मक शक्ति के लिए n, सभी संभव बाइनरी स्ट्रिंग्स पर विचार करें S। याद रखें कि एक बाइनरी स्ट्रिंग बस 1एस और 0एस का एक स्ट्रिंग है, इसलिए बिल्कुल 2^nऐसे तार हैं (जो कि 2शक्ति के लिए है n)। हर एक के लिए हम इस अवधि की गणना कर सकते हैं।

चुनौती कोड लिखने की है जो nइनपुट के रूप में (दो की शक्ति) लेता है और गणना करता है कि इस तरह के कितने अलग-अलग सरणियाँ हैं।

इसके उत्तर n = 1, 2, 4, 8, 16, 32, 64, 128हैं:

1, 2, 6, 32, 320, 6025, 216854, 15128807

के लिए अलग-अलग अवधि सरणियों का पूरा सेट n = 4है:

1, 1, 1
1, 1, 3
1, 1, 4
1, 2, 2
1, 2, 3
1, 2, 4

स्कोर

मैं 10 मिनट तक उबंटू चलाने वाले कंप्यूटर पर आपका कोड चलाऊंगा। आपका स्कोर सबसे बड़ा nहै जिसके लिए आपका कोड उस समय समाप्त हो जाता है। एक टाई के मामले में, जो उत्तर संयुक्त सबसे बड़ी सबसे nतेज जीत है। इस मामले में कि समय पर 1 सेकंड के भीतर एक टाई है, पहला जवाब पोस्ट जीतता है।

भाषाएं और पुस्तकालय

आप अपनी पसंद की किसी भी उपलब्ध भाषा और लाइब्रेरी का उपयोग कर सकते हैं। यदि संभव हो तो लिनक्स में अपना कोड कैसे चलाएं / संकलित करें, इसके लिए एक पूर्ण विवरण शामिल करें। `

आपके कोड को वास्तव में उत्तरों की गणना करनी चाहिए और उदाहरण के लिए, केवल पूर्व-निर्मित मानों का उत्पादन करना चाहिए।

अग्रणी प्रविष्टियाँ

  • 2 मिनट और 21 सेकंड के लिए एन = 128 में सी # पीटर टेलर द्वारा
  • 9 सेकंड में n = 32 के लिए जंग में isaacg द्वारा

इससे मेरे सिर में चोट लगी।
हेनरी

1
चुनौती दिलचस्प है, लेकिन मैं अभी भी "प्री-कॉम्पटेड" और "वास्तव में गणना" उत्तरों के बीच अंतर करने के लिए आपके द्वारा उपयोग किए जाने वाले उद्देश्य मानदंड को नहीं देख सकता । यदि आप, उदाहरण के लिए, समझ नहीं सकते कि मेरा कोड कैसे काम करता है, लेकिन यह विशाल के लिए सही उत्तर देता है n, तो क्या आप इसे स्वीकार करेंगे? यह अच्छी तरह से परिभाषित नहीं है कि हार्डकोडिंग और वास्तविक कंप्यूटिंग के बीच की सीमा कहां है।


1
@ThePirateBay codegolf.meta.stackexchange.com/a/1063/9206 । यह एक मानक नियम है।

2
@Cowsquack सभी लेकिन स्ट्रिंग के पहले तीन अक्षर हैं abcab। सभी लेकिन पिछले 3 अक्षरों है abcab। ये मिलान, और कम संख्या में अक्षरों को हटाने से मेल नहीं खाता।
isaacg

जवाबों:


9

C #, n = 128 लगभग 2:40 में

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandbox
{
    class PPCG137436
    {
        public static void Main(string[] args)
        {
            if (args.Length == 0) args = new string[] { "1", "2", "4", "8", "16", "32", "64", "128" };

            foreach (string arg in args)
            {
                Console.WriteLine(Count(new int[(int)(0.5 + Math.Log(int.Parse(arg)) / Math.Log(2))], 0));
            }
        }

        static int Count(int[] periods, int idx)
        {
            if (idx == periods.Length)
            {
                //Console.WriteLine(string.Join(", ", periods));
                return 1;
            }

            int count = 0;
            int p = idx == 0 ? 1 : periods[idx - 1];
            for (int q = p; q <= 1 << (idx + 1); q++)
            {
                periods[idx] = q;
                if (q == p || q > 1 << idx || p + q - Gcd(p, q) > 1 << idx && UnificationPasses(periods, idx, q)) count += Count(periods, idx + 1);
            }

            return count;
        }

        private static int Gcd(int a, int b)
        {
            while (a > 0) { int tmp = a; a = b % a; b = tmp; }
            return b;
        }

        private static bool UnificationPasses(int[] periods, int idx, int q)
        {
            UnionSet union = new UnionSet(1 << idx);
            for (int i = 0; i <= idx; i++)
            {
                for (int j = 0; j + periods[i] < Math.Min(2 << i, 1 << idx); j++) union.Unify(j, j + periods[i]);
            }

            IDictionary<int, long> rev = new Dictionary<int, long>();
            for (int k = 0; k < 1 << idx; k++) rev[union.Find(k)] = 0L;
            for (int k = 0; k < 1 << idx; k++) rev[union.Find(k)] |= 1L << k;

            long zeroes = rev[union.Find(0)]; // wlog the value at position 0 is 0

            ISet<int> onesIndex = new HashSet<int>();

            // This can be seen as the special case of the next loop where j == -1.
            for (int i = 0; i < idx; i++)
            {
                if (periods[i] == 2 << i) onesIndex.Add((2 << i) - 1);
            }
            for (int j = 0; j < idx - 1 && periods[j] == 2 << j; j++)
            {
                for (int i = j + 1; i < idx; i++)
                {
                    if (periods[i] == 2 << i)
                    {
                        for (int k = (1 << j) + 1; k <= 2 << j; k++) onesIndex.Add((2 << i) - k);
                    }
                }
            }

            for (int i = 1; i < idx; i++)
            {
                if (periods[i] == 1) continue;

                int d = (2 << i) - periods[i];
                long dmask = (1L << d) - 1;
                if (((zeroes >> 1) & (zeroes >> periods[i]) & dmask) == dmask) onesIndex.Add(periods[i] - 1);
            }

            long ones = 0L;
            foreach (var key in onesIndex) ones |= rev[union.Find(key)];

            if ((zeroes & ones) != 0) return false; // Definite contradiction!

            rev.Remove(union.Find(0));
            foreach (var key in onesIndex) rev.Remove(key);

            long[] masks = System.Linq.Enumerable.ToArray(rev.Values);

            int numFilteredMasks = 0;
            long set = 0;
            long M = 0;
            for (int i = 1; i <= idx; i++)
            {
                if (periods[i - 1] == 1) continue;

                // Sort the relevant masks to the start
                if (i == idx) numFilteredMasks = masks.Length; // Minor optimisation: skip the filter because we know we need all the masks
                long filter = (1L << (1 << i)) - 1;
                for (int j = numFilteredMasks; j < masks.Length; j++)
                {
                    if ((masks[j] & filter) != 0)
                    {
                        var tmp = masks[j];
                        masks[j] = masks[numFilteredMasks];
                        masks[numFilteredMasks++] = tmp;
                    }
                }

                // Search for a successful assignment, using the information from the previous search to skip a few initial values in this one.
                set |= (1L << numFilteredMasks) - 1 - M;
                M = (1L << numFilteredMasks) - 1;
                while (true)
                {
                    if (TestAssignment(periods, i, ones, masks, set)) break;
                    if (set == 0) return false; // No suitable assignment found

                    // Gosper's hack with variant to reduce the number of bits on overflow
                    long c = set & -set;
                    long r = set + c;
                    set = (((r ^ set) >> 2) / c) | (r & M);
                }
            }

            return true;
        }

        private static bool TestAssignment(int[] periods, int idx, long ones, long[] masks, long assignment)
        {
            for (int j = 0; j < masks.Length; j++, assignment >>= 1) ones |= masks[j] & -(assignment & 1);
            for (int i = idx - 1; i > 0; i--) // i == 0 is already handled in the unification process.
            {
                if (Period(ones, 2 << i, periods[i - 1]) < periods[i]) return false;
            }

            return true;
        }

        private static int Period(long arr, int n, int min)
        {
            for (int p = min; p <= n; p++)
            {
                // If the bottom n bits have period p then the bottom (n-p) bits equal the bottom (n-p) bits of the integer shifted right p
                long mask = (1L << (n - p)) - 1L;
                if ((arr & mask) == ((arr >> p) & mask)) return p;
            }

            throw new Exception("Unreachable");
        }

        class UnionSet
        {
            private int[] _Lookup;

            public UnionSet(int size)
            {
                _Lookup = new int[size];
                for (int k = 0; k < size; k++) _Lookup[k] = k;
            }

            public int Find(int key)
            {
                var l = _Lookup[key];
                if (l != key) _Lookup[key] = l = Find(l);
                return l;
            }

            public void Unify(int key1, int key2)
            {
                int root1 = Find(key1);
                int root2 = Find(key2);

                if (root1 < root2) _Lookup[root2] = root1;
                else _Lookup[root1] = root2;
            }
        }
    }
}

N = 256 के विस्तार के लिए BigIntegerमास्क के लिए स्विचिंग की आवश्यकता होगी , जो संभवतः n = 128 के लिए प्रदर्शन को बहुत अधिक मारता है नए विचारों के बिना पारित करने के लिए, अकेले n = 256।

लिनक्स के तहत, के साथ संकलन mono-cscऔर निष्पादित करें mono

मूल व्याख्या

मैं एक लाइन-बाय-लाइन विच्छेदन नहीं करने जा रहा हूं, बस अवधारणाओं का अवलोकन।

अंगूठे के एक नियम के रूप में, मैं एक ब्रूट-फोर्स कॉम्बिनेटरिक प्रोग्राम में 2 50 तत्वों के आदेश पर पुनरावृति करके खुश हूं । N = 128 पर जाने के लिए इसलिए एक दृष्टिकोण का उपयोग करना आवश्यक है जो हर बिटस्ट्रिंग का विश्लेषण नहीं करता है। इसलिए बिट स्ट्रिंग्स से लेकर पीरियड सीक्वेंस तक फॉरवर्ड करने के बजाय, मैं पीछे की तरफ काम करता हूं: पीरियड सीक्वेंस को देखते हुए, क्या इसमें कोई कमी है, जो इसका अहसास कराती है? N = 2 x के लिए 2 x (x + 1) / 2 अवधि अनुक्रम (बनाम 2 2 x बिटस्ट्रिंग्स) का एक आसान ऊपरी भाग है ।

कुछ तर्क स्ट्रिंग आवधिकता लेम्मा का उपयोग करते हैं :

आज्ञा देना pऔर qदो अवधि के एक स्ट्रिंग की अवधि हो n। अगर है p + q ≤ n + gcd(p, q)तो gcd(p, q)स्ट्रिंग की अवधि भी।

Wlog मैं मानूंगा कि विचाराधीन सभी बिटस्ट्रिंग्स के साथ शुरू होता है 0

एक अवधि के क्रम को देखते हुए जहां लंबाई 2 i ( हमेशा) के उपसर्ग की अवधि होती है, संभव मानों के बारे में कुछ आसान अवलोकन हैं :[p1 p2 ... pk]pip0 = 1pk+1

  • pk+1 ≥ pkचूंकि एक स्ट्रिंग Sकी अवधि भी किसी भी उपसर्ग की अवधि है S

  • pk+1 = pk हमेशा एक संभावित विस्तार होता है: बस दो बार कई वर्णों के लिए एक ही आदिम स्ट्रिंग दोहराएं।

  • 2k < pk+1 ≤ 2k+1हमेशा एक संभव विस्तार है। यह इस बात को दर्शाने के लिए पर्याप्त है क्योंकि किसी भी अक्षर को लंबाई के एपेरियोडिक स्ट्रिंग में बढ़ाया जा सकता है, जो किसी भी अक्षर को जोड़कर हो सकता है जो इसका पहला अक्षर नहीं है।pk+1 = 2k+1LL+1

    Sxलंबाई 2 k की एक स्ट्रिंग लें जिसकी अवधि है और लंबाई 2 k + 1 की स्ट्रिंग पर विचार करें । जाहिर है एक अवधि 2 कश्मीर +1। मान लीजिए कि इसकी अवधि छोटी है।pkSxySSxySq

    तो फिर आवधिकता से लेम्मा भी एक अवधि है , और चूंकि सबसे बड़ा विभाजक अपने तर्कों से कम या बराबर है और सबसे छोटी अवधि है, हमें 2 k +1 का उचित कारक होना चाहिए । चूँकि इसका भागफल 2 नहीं हो सकता है, हमारे पास है ।2k+1 + q ≤ 2k+1+1 ≤ 2k+1 + gcd(2k+1, q)gcd(2k+1, q)SxySqqq ≤ (2k+1)/3

    अब, चूंकि इसकी अवधि है । लेकिन की अवधि है । हमारे पास दो मामले हैं:q ≤ 2kSxySSxSxpk

    1. gcd(pk, q) = pk, या समकक्ष रूप से बिल्कुल विभाजित करता है ।pkq
    2. pk + q > 2k + gcd(pk, q) ताकि आवधिकता लेम्मा एक छोटी अवधि को मजबूर न करे।

    पहले दूसरे मामले पर विचार करें। , की अवधि के रूप में परिभाषा का विरोध किया । इसलिए हम इस निष्कर्ष पर पहुंचे कि यह एक कारक है ।pk > 2k + gcd(pk, q) - q ≥ 2k+1 - q ≥ 2k+1 - (2k+1)/3 ≥ 2qpkSxpkq

    लेकिन चूंकि qकी अवधि है Sxऔर अवधि है , इसलिए लंबाई का उपसर्ग केवल लंबाई के उपसर्ग की प्रतियां है , इसलिए हम देखते हैं कि यह भी एक अवधि है ।pkSxqq/pkpkpkSxyS

    इसलिए की अवधि या SxySतो या 2 k +1 है। लेकिन हमारे पास दो विकल्प हैं ! सबसे अधिक विकल्प में से एक अवधि देगा , इसलिए कम से कम एक अवधि 2 k +1 देगा। QED।pkyypk

  • आवधिकता लेम्मा हमें कुछ शेष संभावित एक्सटेंशन को अस्वीकार करने की अनुमति देती है।

  • कोई भी एक्सटेंशन, जिसने त्वरित-स्वीकार या त्वरित-अस्वीकार परीक्षा पास नहीं की है, को रचनात्मक रूप से जांचने की आवश्यकता है।

एक बिटस्ट्रिंग के निर्माण को एक अवधि अनुक्रम दिया गया है जो अनिवार्य रूप से एक satisifiable समस्या है, लेकिन इसमें बहुत सारी संरचना है। कर रहे हैं सरल समानता की कमी, प्रत्येक उपसर्ग अवधि से गर्भित तो मैं एक का उपयोग संघ सेट स्वतंत्र समूहों में बिट्स गठबंधन करने के लिए डेटा संरचना। यह n = 64 से निपटने के लिए पर्याप्त था, लेकिन n = 128 के लिए आगे जाना आवश्यक था। मैं तर्क की दो उपयोगी पंक्तियों को नियोजित करता हूं:2k - pk

  1. यदि लंबाई Mका उपसर्ग है और लंबाई के उपसर्ग की अवधि है तो लंबाई के उपसर्ग को समाप्त होना चाहिए । यह उन मामलों में सबसे शक्तिशाली है जो अन्यथा सबसे अधिक स्वतंत्र क्लस्टर होते हैं, जो सुविधाजनक है।01M-1L > MLL1M
  2. यदि लंबाई Mका उपसर्ग है और लंबाई के उपसर्ग के साथ अवधि है और उसके बाद समाप्त होता है तो इसे वास्तव में अंत होना चाहिए । यह विपरीत चरम पर सबसे शक्तिशाली है, जब अवधि अनुक्रम बहुत से लोगों के साथ शुरू होता है।0ML > ML - dd < M0d10d

यदि हम पहले बिट के साथ क्लस्टर को मजबूर करके एक तत्काल विरोधाभास नहीं पाते हैं (शून्य माना जाता है) एक होने के लिए, तो हम अप्रत्याशित समूहों के लिए संभावित मूल्यों पर बल (कुछ माइक्रो-ऑप्टिमाइज़ेशन के साथ) भंग कर देते हैं। ध्यान दें कि आदेश लोगों की अवरोही संख्या में है क्योंकि यदि iवें बिट एक है तो अवधि नहीं हो सकती है iऔर हम उन अवधियों से बचना चाहते हैं जो पहले से ही लागू किए गए से कम हैं। नीचे जाने से एक वैध असाइनमेंट जल्दी खोजने की संभावना बढ़ जाती है।


यह वास्तव में एक बड़ी उपलब्धि है! मैं बहुत प्रभावित हूँ।

@ लेम्बिक, मैंने कोड को सरल और अनुकूलित किया है और n = 128 के लिए रनटाइम को लगभग एक तिहाई घटा दिया है।
पीटर टेलर

1
मुझे यह जानकर अच्छा लगेगा कि आपने इसके लिए कौन सा एल्गोरिदम तैयार किया है। आपके कोड में उल्लेखनीय रूप से कम तर्क हैं और इसमें बहुत ही चतुराई से कुछ किया जाना चाहिए।

7

मेरे लैपटॉप पर जंग, 32, 10s 11s 29s

इसे बिट्साइज़ के साथ कमांड लाइन तर्क के रूप में कॉल करें।

चतुर तकनीकें: संख्याओं के रूप में सीधे बिटस्ट्रिंग्स का प्रतिनिधित्व करती हैं, साइकिल की जांच करने के लिए बिटविडिंग का उपयोग करें। केवल बिटस्ट्रिंग्स के पहले आधे को खोजें, जो 0 से शुरू होते हैं, क्योंकि बिटस्ट्रिंग की अवधि और इसके व्युत्क्रम (1s के लिए 0 एस स्वैप) की समरूपता समान है। यदि अंतिम स्थिति के लिए हर संभावना पहले से ही ठीक हो गई है, तो मैं इसे नहीं खोजता।

अधिक चतुर सामान:

प्रत्येक ब्लॉक को काट देने के लिए (स्ट्रिंग्स जहां बिट्स की पहली छमाही समान होती है) मैं बिटवेक्टर का उपयोग करता हूं, जो हैशसेट की तुलना में बहुत तेज है, क्योंकि अंतिम चक्र की लंबाई को हैशिंग की आवश्यकता नहीं है।

इसके अलावा, मैं चक्र जाँच के पहले चरणों को छोड़ देता हूँ, क्योंकि मैं जानता हूँ कि अंतिम चक्र दूसरे-से-अंतिम चक्र से कम नहीं हो सकता है।

बहुत सारे प्रोफाइलिंग के बाद, मैं अब बता सकता हूं कि लगभग सभी समय का उपयोग उत्पादकता के साथ किया जा रहा है, इसलिए यहां से सुधार करने के लिए एल्गोरिथम सुधार की आवश्यकता होगी, मुझे लगता है। मैंने थोड़ा और समय बचाने के लिए 32 बिट पूर्णांक पर स्विच किया।

//extern crate cpuprofiler;
//use cpuprofiler::PROFILER;

extern crate bit_vec;
use bit_vec::BitVec;

use std::collections::HashSet;

fn cycle_len(num: u32, mask: u32, skip_steps: usize) -> usize {
    let mut left = num >> skip_steps;
    let mut mask = mask >> skip_steps;
    let mut steps = skip_steps;
    loop {
        left >>= 1;
        if left == (num & mask) {
            return steps;
        }
        mask >>= 1;
        steps += 1;
    }
}

fn all_cycles(size_log: usize) -> HashSet<Vec<usize>> {
    let mut set = HashSet::new();
    if size_log == 0 {
        set.insert(vec![]);
        return set;
    } else if size_log == 1 {
        set.insert(vec![0]);
        set.insert(vec![1]);
        return set;
    }
    let size: usize = 1 << size_log;
    let half_size: usize = 1 << size_log - 1;
    let shift_and_mask: Vec<(usize, u32)> = (1..size_log)
        .map(|subsize_log| {
            let subsize = 1 << subsize_log;
            (size - subsize, (1 << (subsize - 1)) - 1)
        })
        .collect();
    let size_mask = (1 << (size - 1)) - 1;
    for block in 0..(1 << (half_size - 1)) as u32 {
        let start: u32 = block << half_size;
        if block % 1024 == 0 {
            eprintln!(
                "{} ({:.2}%): {}",
                start,
                start as f64 / (1u64 << size - 1) as f64 * 100f64,
                set.len()
            );
        }
        let leader = {
            let mut cycles = Vec::new();
            for &(shift, mask) in &shift_and_mask {
                let subnum = start >> shift;
                cycles.push(cycle_len(subnum, mask, 0));
            }
            cycles
        };
        let &end = leader.last().unwrap();
        if (end..size).all(|count| {
            let mut new = leader.clone();
            new.push(count);
            set.contains(&new)
        })
        {
            continue;
        }
        let mut subset = BitVec::from_elem(size, false);
        for num in start..start + (1 << half_size) {
            subset.set(cycle_len(num, size_mask, end), true);
        }
        for (unique_cycle_len, _) in subset.into_iter().enumerate().filter(|x| x.1) {
            let mut new_l = leader.clone();
            new_l.push(unique_cycle_len);
            set.insert(new_l);
        }
    }
    set
}

fn main() {
    let size: f32 = std::env::args().nth(1).unwrap().parse().unwrap();
    let size_log = size.log2() as usize;
    //PROFILER.lock().unwrap().start("./my-prof.profile").unwrap();
    let cycles = all_cycles(size_log);
    //PROFILER.lock().unwrap().stop().unwrap();
    println!(
        "Number of distinct arrays of periods of bitstrings of length {} is {}",
        1 << size_log,
        cycles.len()
    );
}

रखो bit-vec = "0.4.4"अपने Cargo.toml में

यदि आप इसे चलाना चाहते हैं, तो इसे क्लोन करें: github.com/isaacg1/cycle फिर Cargo build --releaseनिर्माण करना, फिर Cargo run --release 32चलाना।


ऐसा लगता है कि 0.16.0 के बाद eprintln को जंग के एक संस्करण की आवश्यकता है। यह काम करता है अगर मैं इसे println में बदल दूं।

यह उत्तर बहुत प्रभावशाली है। timeयह मेरे लैपटॉप पर 27 उपयोगकर्ता सेकंड देता है।

@ लेम्बिक आप जंग के इतने पुराने संस्करण में क्यों हैं? बरसों पहले जंग 1.0 निकली थी।
isaacg

टाइपो :) मेरा मतलब 1.16.0 है। blog.rust-lang.org/2017/03/16/Rust-1.16.html

जंग के लिए newbies, क्या आप ठीक से वर्तनी का उपयोग करने के लिए अपने कोड का संकलन करने के लिए बुरा होगा?

4

जंग , १६

use std::collections::HashSet;
use std::io;

fn main() {
	print!("Enter a pow of two:");
	let mut input_text = String::new();
    io::stdin()
        .read_line(&mut input_text)
        .expect("failed to read from stdin");

    let n_as_string = input_text.trim();
	match n_as_string.parse::<usize>() {
		Ok(n) => {
			let log2 = (n as f64).log(2_f64) as usize;
			if n != 1 << log2 {
				panic!("{} is not a power of two", n);
			}
			let count = compute_count_array(log2, n);
			println!("n = {} -> count = {}", n, count);
		}
		Err(_) => { panic!("{} is not a number", n_as_string); }
	}
}

fn compute_count_array(log2:usize, n: usize) -> usize {
	let mut z = HashSet::new();

	let mut s:Vec<bool> = vec!(false; n);
	loop {
		let mut y:Vec<usize> = vec!();
		for j in 0..log2+1 {
			let p = find_period(&s[0..1<<j]);
			y.push(p);
		}		
		z.insert(y);
		if !next(&mut s) {
			break;
		}
	}
	z.len()
}

#[inline]
fn find_period(s: &[bool]) -> usize {
	let n=s.len();
	let mut j=1;
	while j<n {
		if s[0..n-j] == s[j..n] {
			return j;
		}
		j+=1;
    }
	n
}	

#[inline]
fn next(s:&mut Vec<bool>) -> bool {
	if s[0] {
		s[0] = false;
		for i in 1..s.len() {
			if s[i] {
				s[i] = false;
			} else {
				s[i] = true;
				return true;
			}
		}
		return false
	} else {
		s[0] = true;
	}
	true
}

इसे ऑनलाइन आज़माएं!

संकलन: rustc -O <name>.rs

स्ट्रिंग को बूल वेक्टर के रूप में लागू किया जाता है।

  • nextसंयोजन के माध्यम से समारोह पुनरावृति;

  • find_periodएक बूल टुकड़ा लेता है और अवधि रिटर्न;

  • compute_count_arrayBools के प्रत्येक संयोजन के परिणाम को प्रत्येक "दो की शक्ति" के लिए काम करता है।

सैद्धांतिक रूप से, जब तक 2^nu64 अधिकतम मूल्य से अधिक न हो , कोई अतिप्रवाह की उम्मीद नहीं की जाती है n > 64। इस सीमा को s = [सत्य, सत्य, ..., सत्य] पर एक महंगे परीक्षण से आगे बढ़ाया जा सकता है।

बुरी खबर है: यह n = 16 के लिए 317 देता है, लेकिन मुझे नहीं पता कि क्यों। मैं या तो नहीं जानता कि क्या यह n = 32 के लिए दस मिनट में बना देगा, क्योंकि Vec<bool>यह इस तरह की गणना के लिए अनुकूलित नहीं है।

संपादित करें

  1. मैंने 64 की सीमा को हटाने में कामयाबी हासिल की है n। अब, यह तब तक क्रैश नहीं होगा, जब तक nकि अधिकतम usize पूर्णांक से अधिक न हो ।

  2. मैंने पाया कि पिछला कोड 317 क्यों लौटा n=32। मैं गिनती की गई थी सेट अवधि और नहीं की सरणियों अवधियों की। समान तत्वों के साथ तीन सरणियाँ थीं:

    [1, 2, 3, 3, 8] -> {1, 2, 3, 8}
    [1, 2, 3, 8, 8] -> {1, 2, 3, 8}
    [1, 1, 3, 3, 7] -> {1, 3, 7}
    [1, 1, 3, 7, 7] -> {1, 3, 7}
    [1, 1, 3, 3, 8] -> {1, 3, 8}
    [1, 1, 3, 8, 8] -> {1, 3, 8}
    

अब यह काम कर रहा है। यह अभी भी धीमा है लेकिन यह काम करता है।


यहाँ n = 16 bpaste.net/show/3664e25ebc01 के लिए सभी 320 हैं ।

1
@ लेम्बिक मुझे आपकी सूची के लिए 317 के लिए स्पष्टीकरण मिला।
21

2

सी - 16

यह अतिप्रवाह के 16 cuz से अधिक मूल्यों पर विफल रहता है।

मुझे नहीं पता कि यह कितनी तेजी से एक क्रोमबुक पर cuz im चलाता है जो इसे repl.it पर चलाता है।

बस सवाल को लागू करता है जैसा कि यह पढ़ता है, सभी बिट स्ट्रिंग्स के माध्यम से जाता है, अवधि सरणियों की गणना करता है, और जांचें कि क्या वे पहले से ही गिने जा चुके हैं।

#include "stdio.h"
#include <stdbool.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

int per(int s[], int l) {
  int period = 0;
  while (1) {
    period++;

    bool check = 1;
    int i;
    for (i=0; i<l-period; i++) {
      if (s[i]!=s[i+period]) {
        check = 0;
        break;
      }
    }
    if (check) {
      return period;
    }
  }
}

bool perar(int* s, int l, int* b, int i) {
  int n = 1;
  int j=0;
  while (n<=l) {
    b[i*l+j] = per(s, n);
    n=n<<1;
    j++;
  }

  for (j=0;j<i;j++) {
    int k;
    bool check = 1;
    for(k=0; k<l; k++) {
      if (b[j*l+k] != b[i*l+k]) {
        check = 0;
        break;
      }
    }
    if (check) {
      return 0;
    }
  }
  return 1;
}

int main(int argc, char* argv[]) {
  int n;
  scanf("%d", &n);
  puts("Running...");
  int i;
  int c = 0;
  int* a = malloc(n*sizeof(int));
  int m=pow(2, n);
  int* b = malloc(m*n*sizeof(int));
  for (i=0; i<m; i++) {
    int j;
    for (j=0; j<n; j++) {
      a[j] = (i>>j)&1;
    }
    c+=perar(a, n, b, i);
  }
  printf("Answer: %d\n", c);
  return 0;
}

बस इसे gcc आदि के साथ संकलित करें।


FYI करें - यह 16तब के लिए त्रुटिपूर्ण था जब कोड को बदल दिया गया था ताकि दो mallocएस थे malloc(...int*))और ...**क्रमशः उम्मीद के मुताबिक 16मुद्रित किए गए Answer: 320, हालांकि 32मुद्रित Answer: 0(और बहुत जल्दी)।
जोनाथन एलन

@JonathanAllan ने सामान तय किया, बस b a int * बनाया।
माल्टीसेन

@JonathanAllan 32 चीज़ cuz 2 ** 32 है जो इंट को ओवरफ्लो करती है। इसके अलावा मैं शायद ही स्मृति से बाहर चला जाऊँगा।
माल्टीसेन

@ ThePirateBay मैंने i और m लॉन्ग बनाए, और जब मैं 32 की कोशिश करता हूं तो सिर्फ segfaults होता है। repl.it/JwJl/2 मैं अनुमान लगा रहा हूं कि यह मेमोरी से बाहर है।
माल्टीसेन

@Maltysen। ऐसा लगता है कि यह segfaults है क्योंकि आपने उपलब्ध मेमोरी की कमी के बजाय आवंटन / सौदे में कुछ गड़बड़ कर दी थी। मुझे सेगफॉल्ट हुआ, n = 8लेकिन परिणाम छपने के बाद, जिसका अर्थ है कि स्टैक दूषित है। संभवतः आप कहीं न कहीं आवंटित मेमोरी ब्लॉक (एस) से परे हैं।

2

हास्केल

import qualified Data.Set as S
import Data.Bits

period :: Int -> Int -> Int
period num bits = go (bits-2) (div prefix 2) (clearBit prefix $ bits-1)
  where
  prefix = (2^bits-1) .&. num
  go p x y
    | x == y    = p
    | otherwise = go (p-1) (div x 2) (clearBit y p)

allPeriods :: Int ->  [[Int]]
allPeriods n = map periods [0..div(2^n)2-1]
  where
  periods num = map (period num) powers
  powers = takeWhile (<=n) $ iterate (*2) 2

main = readLn >>= print . S.size . S.fromList . allPeriods

के साथ संकलित करें ghc -O2इसे ऑनलाइन आज़माएं!

के लिए मेरे 6 साल पुराने लैपटॉप हार्डवेयर पर 0.1sec से कम में चलता है n=1699 92 मिनट n=32लगते हैं , इसलिए मैं 9 या 10 का कारक हूं। मैंने एक लुकिंग टेबल में पीरियड्स को कैशिंग करने की कोशिश की है ताकि मुझे बार-बार उन्हें रिकॉल करने की ज़रूरत न पड़े, लेकिन यह जल्दी से मेरी 4 जीबी मशीन पर मेमोरी से बाहर हो जाता है।


10 बंद का कारक होने के बावजूद, आपका कोड बहुत अच्छा है।

@Lembik। धन्यवाद। मैं सिर्फ एक सुधार की कोशिश कर रहा हूं: उपरोक्त कोड लंबाई 1 के सब्सट्रिंग के लिए अवधि की गणना करता है, लेकिन यह पूरी तरह से अनावश्यक है। उन्हें गणना करने के लिए नहीं होने के अलावा, यह कुछ समय भी बचाता है जब पीरियड्स के अनूठे ऐरे ढूंढे जाते हैं, क्योंकि वे सभी एक तत्व से छोटे होते हैं।
निमि

@ लेम्बिक: लंबाई 1 सब्सट्रेट को छोड़ना n = 32 के लिए लगभग 7 मिनट बचाता है। अभी भी बहुत लंबा है।
nimi

अवधि की गणना के लिए एक तेजी से रैखिक एल्गोरिदम है जो मदद कर सकता है।

क्या आप वास्तव में आकार 2 ^ 16 की एक नज़र तालिका नहीं बना सकते हैं? यह बहुत बड़ा नहीं लगता है।

1

पायथन 2 (PyPy), 16

import sys
import math
def do(n):
 masks=[]
 for i in range(n):
  masks+=[(1<<((2<<i)-1))-1]
 s=set()
 bits=1<<n
 for i in xrange(1<<bits):
  r=[0,]*n
  for j in range(len(masks)):
   mask=masks[j]
   k,c=i>>bits-(2<<j),1
   d=k>>1
   while k&mask^d:
    d>>=1
    mask>>=1
    c+=1
   r[j]=c
  s|={tuple(r)}
 return len(s)
print do(int(math.log(int(sys.argv[1]),2)))

: | 32 को इतना लंबा समय क्यों लगता है
ASCII-only

मुझे पता है कि मैं उनमें से आधे को छोड़ सकता हूं लेकिन IDK कैसे: /
केवल

आपका कोड मेरे लिए केवल "कोई नहीं" आउटपुट लगता है। आप इसे कैसे चला रहे हैं? osboxes@osboxes:~/python$ python ascii_user.py 16 None

माफ करना, यह वास्तव में मैं क्या चला नहीं है
केवल

@ लेम्बिक ने अब तय किया
एएससीआईआई-केवल

1

[सी ++], ३२, ४ मिनट

#include <iostream>
#include <vector>

typedef unsigned int u;
template<typename T, typename U>
u Min(T a, U b) {
    return a < b ? a : b;
}

template<typename T, typename U>
u Max(T a, U b) {
    return a > b ? a : b;
}

u Mask(int n) {
    if (n < 0) n = 0;
    return ~((u)(-1) << n);
}
u MASKS[32];

inline u Rshift(u v, int n) {
    return n < 0 ? v >> (-1*n)
    : n > 0 ? v << n
    : n;
}

int GetNextPeriodId(u pattern, int pattern_width, int prior_id) {
    int period = (prior_id % (pattern_width>>1)) + 1;
    int retval = prior_id * pattern_width;

    for (; period < pattern_width; period+=1) {
        u shift = pattern >> period;
        int remainder = pattern_width-period;
        u mask = MASKS[period];

        for (;remainder >= period && !((pattern ^ shift) & mask);
             shift >>= period, remainder -= period);

        if (remainder > period) continue;
        if (remainder == 0 || !((pattern ^ shift) & MASKS[remainder])) {
            retval += (period-1);
            break;
        }
    }
    if (period == pattern_width) {
        retval += pattern_width-1;
    }
    return retval;
}

int ParseInput(int argc, char** argv) {
    if (argc > 1) {
        switch(atoi(argv[1])) {
            case 1:
                return 1;
            case 2:
                return 2;
            case 4:
                return 4;
            case 8:
                return 8;
            case 16:
                return 16;
            case 32:
                return 32;
            default:
                return 0;
        }
    }
    return 0;
}

void PrintId(u id, int patternWidth) {
    for(;patternWidth > 0; id /= patternWidth, patternWidth >>= 1) {
        std::cout << (id % patternWidth)+1 << ",";
    }
    std::cout << std::endl;
}

int TestAndSet(std::vector<bool>& v, int i) {
    int retval = v[i] ? 0 : 1;
    v[i] = true;
    return retval;
}

std::vector<bool> uniques(1<<15);
int uniqueCount = 0;

void FillUniques(u i, int id, int target_width, int final_width) {
    int half_size = target_width / 2;
    u end = 1u<<(half_size-1);
    u mask = MASKS[half_size];
    u lowers[] = { i, (~i)&mask };
    for (u j = 0ul; j < end; j++) {
        u upper = j << half_size;
        u patterns[] = { (upper|lowers[0]), (upper|lowers[1]) };
        for (int k=0; k < sizeof(patterns)/sizeof(patterns[0]); k+=1) {
            int fid = GetNextPeriodId(patterns[k], target_width, id);
            if (target_width != final_width) {
                FillUniques(patterns[k], fid, target_width*2, final_width);
            } else {
                if (TestAndSet(uniques, fid)) {
                    uniqueCount += 1;
                }
            }
        }
    }
}

int main(int argc, char** argv) {
    for (int i = 0; i < 32; i++) {
        MASKS[i] = Mask(i);
    }
    int target_width = 32; // ParseInput(argc, argv);
    if (!target_width) {
        std::cout << "Usage: " << argv[0] << " [1|2|4|8|16|32]" << std::endl;
        return 0;
    }
    if (target_width == 1) {
        std::cout << 1 << std::endl;
        return 0;
    }
    FillUniques(0, 0, 2, target_width);
    std::cout << uniqueCount << std::endl;
    return 0;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.