পিরিয়ডের অ্যারে গণনা করুন


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। পুনরাহ্বান যে একটি বাইনারি স্ট্রিং কেবল একটি স্ট্রিং 1s এবং 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 সেকেন্ড জন্য এন = 32 মধ্যে মরচে isaacg দ্বারা

এতে আমার মাথা খারাপ হয়ে গেছে।
হেনরি

1
চ্যালেঞ্জটি আকর্ষণীয়, তবে আপনি এখনও "পূর্বনির্ধারিত" এবং "প্রকৃত গণনা করা" উত্তরগুলির মধ্যে পার্থক্য করার জন্য অবজেক্টিভ মাপদণ্ড দেখতে পাচ্ছেন না । উদাহরণস্বরূপ, আপনি যদি আমার কোডটি কীভাবে কাজ করে তা বুঝতে না পারেন তবে এটি বিশালটির সঠিক উত্তর দেয় nতবে আপনি কি তা গ্রহণ করবেন? হার্ডকোডিং এবং আসল কম্পিউটিংয়ের মধ্যে সীমানা কোথায় তা এটি যথাযথভাবে সংজ্ঞায়িত হয়নি।


1
@ThePirateBay codegolf.meta.stackexchange.com/a/1063/9206 । এটি একটি মান নিয়ম।

2
@Cowquack All এ স্ট্রিংয়ের প্রথম তিনটি বর্ণ হ'ল abcab। সবশেষে শেষ 3 টি অক্ষর abcab। এই মিলগুলি, এবং অল্প সংখ্যক অক্ষর সরিয়ে ফেলা মেলে না।
isaacg

উত্তর:


9

সি #, এন = 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জন্য মুখোশগুলির জন্য স্যুইচ করা দরকার , যা সম্ভবত এন = 128 এর জন্য নতুন ধারণা ছাড়াই পারফরম্যান্সটিকে খুব বেশি মারে, কেবল এন = 256 দিন let

লিনাক্সের অধীনে, কম্পাইল করুন mono-cscএবং এর সাথে সম্পাদন করুন mono

প্রাথমিক ব্যাখ্যা

আমি একটি লাইন বাই লাইন বিচ্ছেদ করতে যাচ্ছি না, কেবল ধারণাগুলির একটি সংক্ষিপ্ত বিবরণ।

থাম্বের নিয়ম হিসাবে, আমি একটি ব্রুট-ফোর্স কম্বিনেটর প্রোগ্রামে 50 50 টি উপাদান ক্রমের মাধ্যমে পুনরাবৃত্তি করতে পেরে খুশি । এন = 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সর্বদা সম্ভাব্য এক্সটেনশন is এটি দেখানো যথেষ্ট, কারণ দৈর্ঘ্যের একটি এপরিওডিক স্ট্রিং দৈর্ঘ্যের একটি এপরিওডিক স্ট্রিং পর্যন্ত প্রসারিত করা যেতে পারে যে কোনও অক্ষর এটির প্রথম অক্ষর নয় apppk+1 = 2k+1LL+1

    যার Sxদৈর্ঘ্য 2 কে দৈর্ঘ্যের একটি স্ট্রিং নিন এবং 2 কে + 1 দৈর্ঘ্যের স্ট্রিংটি বিবেচনা করুন । স্পষ্টত হয়েছে একটি সময়ের 2 + 1। ধরা যাক এর পিরিয়ড আরও কম।pkSxySSxySq

    তারপরে পর্যায়ক্রমিকভাবে লেমমাও একটি সময়কাল , এবং যেহেতু বৃহত্তম বিভাজক তার তর্কগুলির চেয়ে কম বা সমান এবং সবচেয়ে ছোট সময়কাল, তাই আমাদের 2 কে +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 কে +1। কিন্তু আমরা দুটি বিকল্প আছে ! সর্বাধিক এক পছন্দটি পিরিয়ড দেবে , সুতরাং কমপক্ষে একটি পিরিয়ড 2 কে +1 দেবে। Qed।pkyypk

  • পর্যায়ক্রমের লেমা আমাদের অবশিষ্ট কিছু সম্ভাব্য এক্সটেনশনগুলি প্রত্যাখ্যান করতে দেয়।

  • দ্রুত-গ্রহণযোগ্য বা দ্রুত-প্রত্যাখ্যানিত পরীক্ষায় উত্তীর্ণ হয়নি এমন কোনও এক্সটেনশনের গঠনমূলকভাবে পরীক্ষা করা দরকার।

একটি পিরিয়ড সিকোয়েন্স দেওয়া বিটস্ট্রিং নির্মাণ মূলত একটি সন্তুষ্টিযোগ্যতা সমস্যা, তবে এটির কাঠামোগত পরিমাণ রয়েছে। আছে সহজ সমতা সীমাবদ্ধতার, প্রতিটি উপসর্গ সময়ের ক্ষেত্রে প্রযোজ্য তাই আমি ব্যবহার ইউনিয়ন সেট স্বাধীন ক্লাস্টার মধ্যে বিট একত্রিত ডাটা স্ট্রাকচার। এটি এন = 64 মোকাবেলা করার জন্য যথেষ্ট ছিল, তবে এন = 128 এর জন্য আরও এগিয়ে যাওয়া দরকার ছিল। আমি যুক্তিযুক্ত দুটি কার্যকর লাইন নিযুক্ত করি:2k - pk

  1. যদি দৈর্ঘ্যের উপসর্গ Mহয় এবং দৈর্ঘ্যের উপসর্গের সময়কাল থাকে তবে দৈর্ঘ্যের উপসর্গটি অবশ্যই শেষ হতে হবে । এটি সর্বাধিক শক্তিশালী ক্ষেত্রে অন্যান্য ক্ষেত্রে বেশিরভাগ স্বতন্ত্র ক্লাস্টার থাকতে পারে যা সুবিধাজনক।01M-1L > MLL1M
  2. দৈর্ঘ্য উপসর্গ তাহলে Mহয় এবং দৈর্ঘ্য উপসর্গ0ML > M সময়কাল L - dথাকে d < Mএবং শেষ হয় তবে অবশ্যই এটি অবশ্যই শেষ হওয়া উচিত । বিপরীত চূড়ান্ত ক্ষেত্রে এটি সবচেয়ে শক্তিশালী, যখন পিরিয়ড ক্রমটি অনেকগুলি দিয়ে শুরু হয়।0d10d

যদি আমরা ক্লাস্টারটিকে প্রথম বিট (শূন্য বলে ধরে নেওয়া) এক হয়ে জোর করে তাত্ক্ষণিক দ্বন্দ্ব না পেয়ে থাকি তবে আমরা অরক্ষিত ক্লাস্টারগুলির সম্ভাব্য মানগুলির উপর জোর করে (কিছু মাইক্রো-অপ্টিমাইজেশন সহ) জোর করে ফেলেছি। দ্রষ্টব্য যে ক্রমটি নিম্নোক্ত সংখ্যায় রয়েছে কারণ যদি iথম বিটটি এক হয় তবে সময়কাল হতে পারে নাi এবং আমরা ইতিমধ্যে ক্লাস্টারিং দ্বারা প্রয়োগ করা সময়ের চেয়ে সংক্ষিপ্ততর পিরিয়ডগুলি এড়াতে চাই। নীচে গিয়ে তাড়াতাড়ি একটি বৈধ কার্যনির্বাহী সন্ধানের সম্ভাবনা বাড়িয়ে তোলে।


এটি সত্যিই দুর্দান্ত অর্জন! আমি খুব মুগ্ধ।

@ ল্যাম্বিক, আমি কোডটি সরল ও অপ্টিমাইজ করেছি এবং রান টাইমকে এন = 128 এর প্রায় এক তৃতীয়াংশ দ্বারা হ্রাস করেছি।
পিটার টেলর

1
আপনি এটির জন্য কি অ্যালগরিদম ডিজাইন করেছেন তা জানতে আগ্রহী। আপনার কোডটিতে এটিতে খুব কম যুক্তি রয়েছে এবং অবশ্যই খুব চতুর কিছু করা উচিত।

7

মরিচা, 32, 10s 11s 29sআমার ল্যাপটপে

কমান্ড লাইন আর্গুমেন্ট হিসাবে এটি বিটসাইজে কল করুন।

চতুর কৌশল: বিটস্ট্রিংগুলি সরাসরি সংখ্যা হিসাবে উপস্থাপন করে, চক্র পরীক্ষা করার জন্য বিট বিডলিং ব্যবহার করুন। কেবল বিটস্ট্রিংয়ের প্রথমার্ধটি অনুসন্ধান করুন, 0 দিয়ে শুরু হওয়াগুলি, কারণ বিটস্ট্রিংয়ের পিরিয়ডগুলির অ্যারে এবং এর বিপরীতমুখী (1s এর জন্য 0s পরিবর্তন করা হয়েছে) অভিন্ন। যদি চূড়ান্ত অবস্থানের জন্য প্রতিটি সম্ভাবনা ইতিমধ্যে ঘটে থাকে তবে আমি এটি অনুসন্ধান করি না।

আরও চালাক স্টাফ:

প্রতিটি ব্লকটি নকল করতে (স্ট্রিং যেখানে বিটগুলির প্রথমার্ধ একই হয়) আমি একটি বিটভেক্টর ব্যবহার করি, যা একটি হ্যাশসেটের চেয়ে অনেক দ্রুত, কারণ চূড়ান্ত চক্রের দৈর্ঘ্যে হ্যাশিংয়ের প্রয়োজন হয় না need

এছাড়াও, আমি চক্র চেকিংয়ের প্রথম পদক্ষেপগুলি এড়িয়ে চলেছি কারণ আমি জানি যে চূড়ান্ত চক্র দ্বিতীয় থেকে শেষ চক্রের চেয়ে কম হতে পারে না।

প্রচুর প্রোফাইলিংয়ের পরে, আমি এখন বলতে পারি যে বেশিরভাগ সময় উত্পাদনশীলভাবে ব্যবহার করা হচ্ছে, সুতরাং এখান থেকে উন্নত করার জন্য অ্যালগরিদমিক উন্নতির প্রয়োজন হবে বলে আমি মনে করি। আমি আরও কিছুটা সময় বাঁচাতে 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"আপনার কার্গো.টমলে রাখুন

আপনি যদি এটি চালনা করতে চান তবে এটি ক্লোন করুন: github.com/isaacg1/ سائیکل তারপর Cargo build --releaseতৈরি করতে, তারপরে Cargo run --release 32চালানোর জন্য।


দেখে মনে হচ্ছে যে প্রিন্টলনের জন্য 0.16.0 এর পরে মরিচাটির একটি সংস্করণ প্রয়োজন। যদি আমি এটিকে প্রিন্টনে পরিবর্তন করি তবে এটি কাজ করে।

এই উত্তরটি খুব চিত্তাকর্ষক। timeএটি আমার ল্যাপটপে 27 ব্যবহারকারীর সেকেন্ড দেয়।

@ ল্যাম্বিক আপনি জং এর এত পুরানো সংস্করণে কেন? মরিচা 1.0 বছর আগে বেরিয়েছে।
isaacg

টাইপো :) আমার অর্থ 1.16.0। blog.rust-lang.org/2017/03/16/Rust-1.16.html

মরিচা newbies জন্য, কার্গো ব্যবহার করে আপনার কোডটি কীভাবে সংকলন করবেন তা আপনার বানানটি ঠিক মনে করবে?

4

মরিচা , 16

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একটি bool ফালি নেয় এবং সময়ের ফেরৎ;

  • compute_count_arrayBools প্রতিটি সমন্বয় subsequence প্রতিটি "দুই শক্তি" জন্য পেশা আছে।

তাত্ত্বিকভাবে, 2^nu64 সর্বাধিক মান অতিক্রম না করা পর্যন্ত কোনও ওভারফ্লো আশা করা যায় নাn > 64 । এই সীমাটি s = [সত্য, সত্য, ..., সত্য] এর জন্য একটি ব্যয়বহুল পরীক্ষা দিয়ে পৌঁছানো যেতে পারে।

খারাপ খবর হ'ল এটি এন = 16 এর জন্য 317 ফেরত দেয় তবে কেন তা আমি জানি না। আমি জানি না এটি এন = 32 এর জন্য দশ মিনিটের মধ্যে তৈরি করবে কিনা, যেহেতু Vec<bool>এই ধরণের গণনার জন্য অনুকূলিত করা হয়নি।

সম্পাদনা

  1. আমি 64 এর সীমা সরিয়ে ফেলতে সক্ষম হয়েছি n। এখন, nসর্বোচ্চ ব্যবহারের পূর্ণসংখ্যার চেয়ে বড় না হওয়া পর্যন্ত এটি ক্রাশ হবে না won't

  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 টি ধন্যবাদ ব্যাখ্যা পেয়েছি।
jferard

2

সি - 16

এটি ওভারফ্লো 16 কিউজেরও বেশি মানগুলিতে ব্যর্থ হয়।

আমার কোনও ধারণা নেই যে এটি ক্রপবুকটিতে repl.it- তে চালাচ্ছে কিউজ আইএম fast

পড়ার সাথে সাথে কেবল প্রশ্নটি প্রয়োগ করে, সমস্ত বিট স্ট্রিংয়ের মধ্য দিয়ে যায়, পিরিয়ড অ্যারে গণনা করে এবং তারা ইতিমধ্যে গণনা করা হয়েছে কিনা তা পরীক্ষা করে।

#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;
}

এটি কেবল জিসিসি ইত্যাদির সাথে সংকলন করুন


অবগতির জন্য - এটি জন্য erroring ছিল 16তারপর কোড এতটা পাল্টে দেয় যে দুই mallocগুলি ছিল malloc(...int*))এবং ...**যথাক্রমে 16মুদ্রিত Answer: 320আশানুরূপ তবে 32মুদ্রিত Answer: 0(এবং প্রশংসনীয় দ্রুত)।
জোনাথন অ্যালান

@ জোনাথান অ্যালান স্টাফ ঠিক করেছেন, সবেমাত্র বি এনটি * করেছেন।
মাল্টেসেন

@ জোনাথান অ্যালান 32 টি বিষয়টি সিউজ 2 ** 32 ইন্টি-ইনফ্লো করছে। এছাড়াও আমি স্মৃতি থেকে দূরে থাকব।
মাল্টেসেন

@ দ্য পাইরেটবে আমি আমি এবং আমার দীর্ঘত্ব তৈরি করেছি এবং আমি যখন 32 বার চেষ্টা করি তখন কেবল সেগফাল্ট করে rep repl.it/JwJl/2 আমি অনুমান করছি এটি স্মৃতিশক্তি হারিয়েছে
মালটিসেন

@Maltysen। দেখে মনে হচ্ছে এটি উপলব্ধ হয়ে গেছে কারণ আপনি উপলব্ধ মেমরির অভাবের চেয়ে বরাদ্দ / অবলম্বনে কিছু গণ্ডগোল করেছেন। আমি সেগফল্ট পেয়েছি n = 8তবে ফলাফলটি মুদ্রণের পরে, যার অর্থ স্ট্যাকটি দূষিত। সম্ভবত আপনি বরাদ্দ মেমরি ব্লক (গুলি) এর বাইরেও কোথাও লিখন করছেন।

2

Haskell,

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.1 সেকেন্ডেরও কম সময়ে চলে n=16n=32লাগে 99 92min, তাই আমি ফ্যাক্টর 9 বা 10 বন্ধ করছি। আমি পর্যায়ক্রমের টেবিলটিতে পিরিয়ডগুলি ক্যাশে করার চেষ্টা করেছি যাতে আমার এগুলি বারবার পুনরায় গণনা করতে না হয়, তবে এটি আমার 4 জিবি মেশিনে মেমরির বাইরে চলে যায়।


10 অফ অফ ফ্যাক্টর হওয়া সত্ত্বেও, আপনার কোডটি দেখতে খুব ভাল।

@Lembik। ধন্যবাদ। আমি কেবল একটি উন্নতির চেষ্টা করছি: উপরের কোডটি দৈর্ঘ্য 1 এর সাবস্ট্রিংয়ের জন্য পিরিয়ড গণনা করে তবে এটি সম্পূর্ণ অপ্রয়োজনীয়। এগুলি গণনা না করার পাশাপাশি, পিরিয়ডগুলির অনন্য অ্যারেগুলি সন্ধান করার সময় এটি কিছুটা সময় সাশ্রয় করে কারণ এগুলি সমস্ত এক উপাদানই খাটো।
নিমি

@ ল্যাম্বিক: দৈর্ঘ্য 1 সাবস্ট্রিংগুলি বাদ দিয়ে এন = 32 এর জন্য প্রায় 7 মিনিট সাশ্রয় হয়। এখনও অনেক দীর্ঘ।
নিমি

পিরিয়ড গণনা করার জন্য একটি দ্রুত রৈখিক অ্যালগরিদম রয়েছে যা সাহায্য করতে পারে।

আপনি কি আকার 2 ^ 16 এর সন্ধানের টেবিলটি তৈরি করতে পারবেন না? এটা খুব বড় মনে হয় না।

1

পাইথন 2 (পাইপাই), 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- কেবল

আমি জানি আমি তাদের অর্ধেক এড়িয়ে যেতে পারি তবে আইডি কে কীভাবে: /
ASCII- কেবল

আপনার কোডটি আমার কাছে কেবল "কিছুই নয়" আউটপুট বলে মনে হচ্ছে। আপনি এটি কিভাবে চালাচ্ছেন? osboxes@osboxes:~/python$ python ascii_user.py 16 None

বোকা দুঃখিত, এটি আসলে আমি যা চালাই তা নয়
ASCII-

@ ল্যাম্বিক এখনই স্থির হয়েছে
ASCII- কেবল

1

[সি ++], 32, 4 মিনিট

#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;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.