परफेक्ट लाइसेंस प्लेट्स


33

परफेक्ट लाइसेंस प्लेट्स

कुछ साल पहले शुरू करते हुए, मैंने ड्राइविंग करते समय खुद को एक छोटा सा खेल बनाया: अगर पास की लाइसेंस प्लेट्स "सही" हैं तो जाँच करें। जब आप एक पाते हैं तो यह अपेक्षाकृत दुर्लभ, लेकिन रोमांचक होता है।

यह देखने के लिए कि लाइसेंस प्लेट सही है या नहीं:

  1. अक्षर = A = 1, B = 2, ... Z = 26 के साथ योग करें।
  2. अंकों के प्रत्येक लगातार हिस्सा लें, और उन्हें योग करें; इनमें से प्रत्येक को एक साथ गुणा करें।

यदि भाग 1 और भाग 2 में मान समान हैं, तो बधाई! आपको एक पूर्ण लाइसेंस प्लेट मिल गई है!

उदाहरण

License plate: AB3C4F

Digits -> 3 * 4 
        = 12
Chars  -> A + B + C + F 
        = 1 + 2 + 3 + 6 
        = 12
12 == 12 -> perfect!


License plate: G34Z7T

Digits -> (3 + 4) * 7 
        = 49
Chars  -> G + Z + T 
        = 7 + 26 + 20 
        = 53
49 != 53 -> not perfect!


License plate: 10G61

Digits -> (1 + 0) * (6 + 1)
        = 7
Chars  -> G
        = 7
7 == 7 -> perfect!

चुनौती

मैंने उदाहरण के रूप में लंबाई 5 और 6 की लाइसेंस प्लेट का उपयोग किया, लेकिन यह प्रक्रिया किसी भी प्लेट की लंबाई के लिए मान्य है। आपकी चुनौती दी गई लंबाई N के लिए है, उस लंबाई की सही लाइसेंस प्लेटों की संख्या लौटाएं। चुनौती के प्रयोजनों के लिए, एक मान्य लाइसेंस प्लेट अंक 0-9 और वर्ण AZ का कोई संयोजन है। प्लेट में एक चरित्र और एक अंक दोनों होने चाहिए जिसमें संभावित रूप से परिपूर्ण माना जा सके। प्रयोजनों की जाँच करने के लिए, मेरे द्वारा दिए गए मूल्य हैं (हालांकि मैं उनकी शुद्धता, हाहा के बारे में 100% नहीं हो सकता)

N < 2: 0
N = 2: 18
N = 3: 355
N = 4: 8012 

टिप्पणियाँ

यदि किसी तरह यह आपकी भाषा में समस्या को सरल बनाता है, तो आप किसी दिए गए N के लिए सही लाइसेंस प्लेटों के अनुपात को कम से कम 2 महत्वपूर्ण चरणों तक आउटपुट कर सकते हैं ।

N < 2: 0
N = 2: 0.0138888...
N = 3: 0.0076088...
N = 4: 0.0047701...

या, आप समतुल्य मूल्य मॉड 256 का उत्पादन कर सकते हैं

N < 2: 0
N = 2: 18
N = 3: 99
N = 4: 76

सबसे छोटी जीत!


2
साइट पर आपका स्वागत है! मुझे लगता है कि यह एक अच्छी चुनौती है, लेकिन अतिरिक्त अनुमत आउटपुट वास्तव में जवाब देने के लिए कठिन बनाते हैं। पीपीसीजी उद्देश्य जीतने के मानदंडों की तलाश करता है, और यह करना मुश्किल है कि जब बहुत सारी स्वतंत्रता हो; यह केवल आउटपुट स्वरूप नहीं बदलता है, यह वास्तव में वही बदलता है जो आप आउटपुट की अनुमति देते हैं। मैं अन्य विकल्पों को संपादित करने की सलाह दूंगा और इसके लिए सही लाइसेंस प्लेटों की संख्या को आउटपुट करने की आवश्यकता होगी N
हाइपरन्यूट्रिनो

11
मैं व्यक्तिगत रूप से इस चुनौती का अधिक आनंद ले सकता हूं अगर यह केवल यह पुष्टि कर रहा था कि दी गई लाइसेंस प्लेट सही है या नहीं (विशेष रूप से क्योंकि आपके पास परीक्षण मामलों के लिए निश्चित संख्या नहीं है। यह संभवतः ठीक है, हालांकि, जब तक कि संभावित गणना के परिणाम नहीं मिलेंगे। कम कर रहे हैं। हालांकि अन्य लोगों को कैसा लगता है, इस बारे में निश्चित नहीं है। हालांकि अच्छा विचार है!
मिल्डलीवेटकॉस्ट

4
मैं मिस्टाहा फिगर्स से सहमत हूं; मुझे लगता है कि इस तरह से यह एक पैटर्न खोजने के बारे में अधिक है, जो अभी भी एक दिलचस्प चुनौती है, लेकिन मुझे लगता है कि यह अधिक जवाब आकर्षित कर सकता है अगर यह सिर्फ एक सत्यापन जांच थी। हालांकि अच्छी चुनौती!
हाइपरएन्यूट्रीनो

1
मैंने एक निकट से संबंधित चुनौती पोस्ट की है , उम्मीद है कि यह इस अद्भुत सवाल पर ध्यान आकर्षित करेगा, साथ ही इसे थोड़ा सरल करेगा, केवल (लगभग) सही लाइसेंस प्लेट की जांच कर रहा है।
श्री एक्सकोडर

1
@carusocomputing मैंने पूरी कोशिश की लेकिन खाली हाथ आया। मैंने इसे अपने गणित शिक्षक को भेजा और वह अब तक खाली है
क्रिस्टोफर

जवाबों:


9

पायथन 3.6, 150 बाइट्स

f=lambda n,t=-1,p=-1,a=0:sum(f(n-1,*((t,c+p*(p>=0),a),((t<0 or t)*(p<0 or p),-1,a-c))[c<0])for c in range(-26,10))if n else 0<(t<0 or t)*(p<0 or p)==a

परिणाम:

f(2) = 18
f(3) = 355
f(4) = 8012
f(5) = 218153

स्पष्टीकरण के साथ अनगुल्ड संस्करण:

digits=[*range(10)]
letters=[*range(1,27)]

def f(n, dt=-1, dp=-1, lt=0):
    if n:
        for d in digits:
            yield from f(n - 1,
                         dt,
                         d if dp < 0 else dp + d,
                         lt
                         )

        for l in letters:
            yield from f(n - 1,
                         dp if dt < 0 else dt if dp < 0 else dt*dp,
                         -1,
                         lt + l
                         )
    else:
        yield 0 < lt == (dt<0 or dt)*(dp<0 or dp)

समस्या एक ऐसे पेड़ की खोज करने के लिए उबलती है जिसमें पेड़ का प्रत्येक स्तर लाइसेंस प्लेट नंबर की स्थिति से मेल खाता हो और प्रत्येक नोड में 36 बच्चे (10 अंक और 26 अक्षर) हों। यह कार्य वृक्ष की पुनरावर्ती खोज करता है, जैसे ही वह जाता है अंक और अक्षरों के लिए मानों को जमा करता है।

n is the number of levels to search. 
dp accumulates the sum of a group of digits.
dt accumulates the product of the digit sums.
lt accumulates the sum of the letter values.

For dp and dt, a value < 0 indicates it is not initialized.

गोल्फ में शामिल है, जेनरेटरों के लिए छोरों को परिवर्तित करना:

sum(f(n-1, 
      dt,
      d if dp < 0 else dp + d,
      lt) for d in digits)
+
sum(f(n-1,
      dp if dt<0 else dt if dp<0 else dt*dp,
      -1,
      lt+l) for l in letters)

फिर जनरेटर का संयोजन। अक्षरों को A, Z, को -1 से -26 तक और 0 से 9. के अंकों को सांकेतिक शब्दों में बदलना। तो योग बनता है:

sum(f(n-1, *args) for c in range(-26, 10)),

जहां args है:

((dp if dt<0 else dt if dp<0 else dt*dp, -1, lt-l) if c <0 else
 (dt, d if dp<0 else dp+d, lt))

बाकी गोल्फिंग फंक्शन को लैम्ब्डा में परिवर्तित कर रहा है, वेरिएबल नाम को छोटा कर रहा है और एक्सप्रेशन को सरल बना रहा है।


यह एक स्पष्ट समाधान है, रनटाइम क्या होगा? n*n*log(n)या ऐसा ही कुछ?
मैजिक ऑक्टोपस Urn

@carusocomputing धन्यवाद। समाधान अभी भी दी गई लंबाई के सभी संभावित क्रम को उत्पन्न करता है, इसलिए इसमें अन्य समाधानों की तरह ही जटिलता है। K ** n जैसा कुछ, जहाँ k अक्षर में प्रतीकों की संख्या है (उदाहरण के लिए, 10 अंक + 26 अक्षर = 36) और n एक लाइसेंस प्लेट पर प्रतीकों की संख्या है। N = 5 के लिए इसे चलाने के लिए 36 ^ 5 = 60,466,176 क्रमोन्नति की जाँच करने की आवश्यकता होती है और एक या दो मिनट लगते हैं (संस्मरण इसे गति दे सकता है, लेकिन बहुत सारे बाइट्स ;-)) खर्च होंगे।
रूटट्वो

6

दिल्लोग एपीएल, 57 56 बाइट्स

+/(+/0⌈a-9)=×/c*⍨-2-/0,⌈\(+\a×b)×c←2>/0,⍨b←9≥a←↑1↓,⍳⎕⍴36

(मान लिया गया ⎕io←0)

aसभी वैध लाइसेंस प्लेटों को छोड़कर (इनको छोड़कर 00...0) अंकों के लिए 0-9, अक्षरों के लिए 10-35

b जहां अंक होते हैं, उसके लिए बिटमास्क

c लगातार अंकों के प्रत्येक समूह में अंतिम अंक के लिए बिटमास्क


1-4 के लिए ऑनलाइन प्रयास करें 4 के लिए अधिक मेमोरी की आवश्यकता है, लेकिन इसके आसपास भी तरीके हैं!
आदम

4

पायथन 2, 359 295 बाइट्स

बल्कि लंबे समय; यह तुच्छ समाधान है। मुझे विश्वास है कि यह सही है, हालांकि यह चुनौती में परीक्षण के मामलों से मेल नहीं खाता है। जो समाधान मुझे मिल रहे हैं वे दादा के उत्तरों से मेल खाते हैं।

import itertools as i,re as r,string as s
print len([''.join(x)for x in i.product(s.lowercase+s.digits,repeat=input())if(lambda t:r.search('\\D',t)and r.search('\\d',t)and reduce(int.__mul__,[sum(map(int,k))for k in r.split('\\D+',t)if k])==sum([k-96 for k in map(ord,t) if k>96]))(''.join(x))])

-64 बाइट्स @numbermaniac के सुझावों के लिए धन्यवाद


1
आप c (x) और अंतिम पंक्ति में लगभग तीन बाइट्स बचा सकते हैं; 96 और के बीच एक स्थान को हटा दें for; के बीच map(ord,x)और if; और अंतिम पंक्ति में, के बीच .join(x)और for। मुझे लगता है कि अगर आप लंबोदा के कार्यों को फिर से परिभाषित करते हैं तो आप और भी अधिक बचत कर सकते हैं।
नंबरमानिया

@numbermaniac धन्यवाद! (64 बाइट्स टोटल)
हाइपरएनुट्रिनो

4

पायथन 2 , 291 287 276 273 बाइट्स

lambda n:sum(1for x in s.product(y+z,repeat=n)if(lambda p,s=set:reduce(int.__mul__,[sum(map(int,i))for i in re.findall(r"\d+",p)],1)==sum(ord(i)-64for i in p if ord(i)>64)and s(p)&s(y)and s(p)&s(z))(''.join(x)))
import re,itertools as s,string as t
y=t.uppercase
z=t.digits

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


परिणाम:

0 0
1 0
2 18
3 355
4 8012

3

पर्ल 5 , 117 बाइट्स

कोड + -pध्वज के 116 बाइट्स ।

$"=",";@F=(A..Z,0..9);map{$r=1;$r*=eval s/./+$&/gr for/\d+/g;$r+=64-ord for/\pl/g;$\+=!$r*/\pl/*/\d/}glob"{@F}"x$_}{

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

यह काफी अडॉप्टिमल लगता है, लेकिन मैं अभी विचारों से बाहर हूं।
कोड अपने आप में बहुत अयोग्य है क्योंकि यह a..z,0..9लंबाई के हर क्रमपरिवर्तन की गणना करता है n(यह लगभग 1 सेकंड के लिए n=3, ~ 15 सेकंड के लिए n=4और ~ 7 मिनट के लिए n=5) लेता है ।
एल्गोरिथ्म काफी सीधे आगे है: आकार की हर संभव प्लेट के लिए n(उत्पन्न glob"{@F}"x$_- globऑपरेटर काफी जादू है), $r*=eval s/./+$&/gr for/\d+/g;अंकों के हर भाग के उत्पाद की गणना करता है, और $r+=64-ord for/\pl/gइसे अक्षरों का वजन घटाता है। फिर, हम काउंटर को बढ़ाते हैं $\यदि $rहै 0( !$r) और यदि प्लेट में नंबर और अक्षर हैं ( /\pl/*/\d/)। झंडा $\के लिए अंत में स्पष्ट रूप से मुद्रित किया जाता है -p

ध्यान दें कि संख्या मैं प्राप्त कर रहे हैं n=2 -> 18, n=3 -> 355, n=4 -> 8012, n=5 -> 218153। मुझे पूरा यकीन है कि ये सही हैं, लेकिन मैं गलत हो सकता हूं, इस मामले में मुझे बताएं और मैंने इस जवाब को हटा दिया।


3

एपीएल (डायलॉग) , 71 बाइट्स

पूर्ण कार्यक्रम निकाय। N. N≥4 के लिए संकेतों को भारी मात्रा में स्मृति और संगणना की आवश्यकता होती है।

+/((+/⊢⍳∩)∘⎕A=(×/'\d+'S{+/⍎¨⍵.Match}))¨l/⍨∧⌿∨/¨c∘.∊l←,(∊c←⎕DA)∘.,⍣⎕⊂⍬

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


2

स्काला, 265 बाइट्स

(n:Int)=>{val i=('A'to'Z')++('0'to'9');Seq.fill(n)(i).flatten.combinations(n).flatMap(_.permutations).map(_.mkString).count(l=>"(?=.*[A-Z])(?=.*\\d)".r.findAllIn(l).size>0&&l.map(_-64).filter(_>0).sum==l.split("[A-Z]").filter(""<).map(_.map(_-48).sum).reduce(_*_))}

स्पष्टीकरण:

(n:Int) => {
    val i = ('A' to 'Z') ++ ('0' to '9');                       // All license plates available characters.
    Seq.fill(n)(i).flatten                                      // Simulate combination with repetition (each character is present n times)
        .combinations(n)                                        // and generate all combinations of size n (all license plates).
        .flatMap(_.permutations)                                // For each combination, generate all permutations (ex. : Seq('A', '1') => Seq('A', '1') and Seq('1', 'A')), and
        .map(_.mkString)                                        // convert each permutation to String (Seq('A', '1') => "A1").
        .count ( l =>                                           // Then count all strings having :
            "(?=.*[A-Z])(?=.*\\d)".r.findAllIn(l).size > 0 &&   // at least 1 character and 1 digit and
            l.map(_ - 64).filter(_ > 0).sum ==                  // a sum of characters (> 'A' or > 64) equals to
            l.split("[A-Z]").filter(""<)
                .map(_.map(_ - 48).sum)
                .reduce(_*_)                                    // the product of sum of digits groups (split String by letters to get digits groups)
        )
}

टिप्पणियाँ :

  • -64और -48एक को बदलने के लिए उपयोग किया जाता है Charइसके लिए (क्रमशः पत्र और अंक) Intमूल्य ( 'A' - 64 = 1, 'B' - 64 = 2, ..., '9' - 48 = 9)
  • यदि कोई अक्षर (उदाहरण:) से शुरू होता है तो मूल्यों l.split("[A-Z]").filter(""<)को खत्म करने के लिए फ़िल्टर का उपयोग किया जाता है । एक बेहतर और छोटा समाधान हो सकता है""l"A1".split("[A-Z]") => Array("", 1)

परीक्षण के मामलों :

val f = (n:Int) => ...  // assign function
(1 to 5).foreach ( i =>
    println(s"N = $i: ${f(i)}")
)

परिणाम:

N = 1: 0
N = 2: 18
N = 3: 355
N = 4: 8012
N = 5: 218153

फ़ंक्शन बहुत धीमा है n > 4क्योंकि सभी संयोजनों को उत्पन्न किया जाना चाहिए।


2

जावा, 382 365 बाइट्स

  • केविन क्रूज़सेन की बदौलत 17 बाइट्स बचीं

golfed

int h(String s){int m=0;for(int c:s.toCharArray())m+=c-48;return m;}
int g(String t){int d=1,c=0;for(String s:t.split("[^0-9]"))d*=h(s);for(String s:t.split("[^A-Z]"))c+=s.charAt(0)-65;return d==c?1:0;}
int f(String t,int n){int m=0;if(t.length()==n)return g(t);for(int d=48;d<58;)m+=f(t+d++,n);for(int c=65;c<91;)m+=f(t+c++,n);return m;}
int s(int n){return f("",n);}

विस्तृत

// return sum of adjecent digits
int h(String s)
{
    int sum = 0;
    for(char c : s.toCharArray()) sum += c-'0';
    return sum;
}

// check if perfect
int g(String t)
{
    int d = 1;
    int c = 0;

    for(String s : t.split("[^0-9]")) d *= h(s);
    for(String s : t.split("[^A-Z]")) c += s.charAt(0)-'A';

    return d == c ? 1 : 0;
}

// tree of enumerations
int f(String t, int n)
{
    // base case
    if(t.length() == n)
    {
        return g(t);
    }

    // enumeration
    int sum = 0;
    for(char d='0'; d<='9'; d++) sum += f(t+d, n);
    for(char c='A'; c<='Z'; c++) sum += f(t+c, n);

    return sum;
}

int s(int n){ return f("",n); }

मुझे लगता है कि आपको एक फ़ंक्शन की आवश्यकता है जो केवल nइनपुट के रूप में लेता है ।
क्रिश्चियन सेवर्स

@ChristianSievers तय हुए
खालिद.के।

1
अपने वर्तमान कोड के लिए गोल्फ के लिए कुछ चीजें: int h(String s){int m=0;for(int c:s.toCharArray())m+=c-48;return m;}int g(String t){int d=1,c=0;for(String s:t.split("[^0-9]"))d*=h(s);for(String s:t.split("[^A-Z]"))c+=s.charAt(0)-65;return d==c?1:0;}int f(String t,int n){int m=0;if(t.length()==n)return g(t);for(int d=48;d<58;)m+=f(t+d++,n);for(int c=65;c<91;)m+=f(t+c++,n);return m;}int s(int n){return f("",n);}( 365 बाइट्स ) आप अपने वर्तमान संस्करण की तुलना मेरे द्वारा किए गए परिवर्तनों को देखने के लिए कर सकते हैं (इस टिप्पणी के शेष भाग में फिट होने के लिए बहुत अधिक)। :)
केविन क्रूज़सेन

@ केविनक्रूजसेन thx, 17 बाइट्स अभी बंद
खालिद.के

2

जीएपी , 416 बाइट्स

कोड आकार और लगातार समय से बहुत दूर नहीं जीतेंगे, लेकिन गणित का उपयोग बहुत तेजी से करते हैं!

x:=X(Integers);
z:=CoefficientsOfUnivariatePolynomial;
s:=Size;

f:=function(n)
 local r,c,p,d,l,u,t;
 t:=0;
 for r in [1..Int((n+1)/2)] do
  for c in [r..n-r+1] do
   l:=z(Sum([1..26],i->x^i)^(n-c));
   for p in Partitions(c,r) do
    d:=x;
    for u in List(p,k->z(Sum([0..9],i->x^i)^k)) do
     d:=Sum([2..s(u)],i->u[i]*Value(d,x^(i-1))mod x^s(l));
    od;
    d:=z(d);
    t:=t+Binomial(n-c+1,r)*NrArrangements(p,r)*
         Sum([2..s(d)],i->d[i]*l[i]);
   od;
  od;
 od;
 return t;
end;

अनावश्यक व्हॉट्सएप को निचोड़ने और 416 बाइट्स के साथ एक लाइन प्राप्त करने के लिए, इसके माध्यम से पाइप करें:

sed -e 's/^ *//' -e 's/in \[/in[/' -e 's/ do/do /' | tr -d \\n

मेरा पुराना "विंडोज एक्सपी के लिए डिज़ाइन किया गया" लैपटॉप f(10)एक मिनट से भी कम समय में गणना कर सकता है और एक घंटे के भीतर बहुत आगे बढ़ सकता है:

gap> for i in [2..15] do Print(i,": ",f(i),"\n");od;
2: 18
3: 355
4: 8012
5: 218153
6: 6580075
7: 203255386
8: 6264526999
9: 194290723825
10: 6116413503390
11: 194934846864269
12: 6243848646446924
13: 199935073535438637
14: 6388304296115023687
15: 203727592114009839797

यह काम किस प्रकार करता है

मान लीजिए कि हम पहले पैटर्न को फिट करने वाले पूर्ण लाइसेंस प्लेटों की संख्या जानना चाहते हैं LDDLLDL, जहां Lएक अक्षर को Dदर्शाता है और एक अंक को दर्शाता है। मान लें कि हमारे पास lसंख्याओं की एक सूची l[i]है जो अक्षरों को मूल्य देने के तरीकों की संख्या बताती है i, और dअंकों से प्राप्त मूल्यों के लिए एक समान सूची । फिर सामान्य मूल्य के साथ सही लाइसेंस प्लेटों की संख्या iबस है l[i]*d[i], और हम अपने सभी पैटर्न के साथ सभी पूर्ण लाइसेंस प्लेटों की संख्या प्राप्त करते हैं i। आइए इस योग को प्राप्त करने के संचालन को निरूपित करते हैं l@d

अब भले ही इन सूचियों को प्राप्त करने का सबसे अच्छा तरीका सभी संयोजनों और गिनती की कोशिश करना था, हम अक्षरों और अंकों के लिए स्वतंत्र रूप से ऐसा कर सकते हैं, 26^4+10^3मामलों के बजाय 26^4*10^3 मामलों को देखते हुए जब हम सभी प्लेटों को पैटर्न फिटिंग करते हैं। लेकिन हम बहुत बेहतर कर सकते हैं: lसिर्फ अक्षरों की सूची है, (x+x^2+...+x^26)^kजहां kपत्रों की संख्या है, यहां 4

इसी प्रकार, हम kगुणांक के रूप में अंकों की एक संख्या में अंकों का योग प्राप्त करने के तरीकों की संख्या प्राप्त करते हैं (1+x+...+x^9)^k। यदि अंकों का एक से अधिक भाग है, तो हमें संबंधित सूचियों को एक ऑपरेशन के साथ संयोजित करना होगा d1#d2जो कि उस स्थान पर iहो d1[i1]*d2[i2]जहाँ सभी का योग हो i1*i2=i। यह डिरिचलेट कनवल्शन है, जो सिर्फ उत्पाद है अगर हम लिस्ट को डार्चलेट श्रृंखला के गुणांक के रूप में व्याख्या करते हैं। लेकिन हमने पहले ही उन्हें बहुपद (परिमित शक्ति श्रृंखला) के रूप में उपयोग किया है, और उनके लिए ऑपरेशन की व्याख्या करने का कोई अच्छा तरीका नहीं है। मुझे लगता है कि यह बेमेल हिस्सा है जो एक सरल सूत्र को खोजने के लिए कठिन बनाता है। चलो वैसे भी बहुपद पर इसका उपयोग करें और एक ही अंकन का उपयोग करें #। गणना करना आसान है जब एक ऑपरेंड एक मोनोमियल है: हमारे पासp(x) # x^k = p(x^k)। इस तथ्य के साथ कि यह बिलिनियर है, यह गणना करने के लिए एक अच्छा (लेकिन बहुत कुशल नहीं) तरीका देता है।

ध्यान दें कि kअक्षर अधिकतम मूल्य देते हैं 26k, जबकि k एकल अंक एक मान दे सकते हैं 9^k। इसलिए हम dबहुपद में अक्सर अनावश्यक शक्तियों को प्राप्त करेंगे । इनसे छुटकारा पाने के लिए हम मोडुलो की गणना कर सकते हैं x^(maxlettervalue+1)। यह एक बड़ी गति देता है और, हालांकि, मैंने तुरंत ध्यान नहीं दिया, यहां तक ​​कि गोल्फिंग में भी मदद करता है, क्योंकि अब हम जानते हैं कि डिग्री dबड़ी नहीं होती है l, जो अंतिम में ऊपरी सीमा को सरल बनाती है Sum। हम ( modपहले Valueटिप्पणियों को देखें) में एक गणना करके और भी बेहतर गति प्राप्त करते हैं, और #निचले स्तर पर पूरी गणना करने से एक अविश्वसनीय गति मिलती है। लेकिन हम अभी भी एक गोल्फ समस्या के लिए एक वैध जवाब बनने की कोशिश कर रहे हैं।

तो हम अपने मिल गया है lऔर dपैटर्न के साथ सही लाइसेंस प्लेटों की संख्या की गणना करने के लिए उनका उपयोग कर सकते हैं LDDLLDL। पैटर्न के लिए भी यही संख्या है LDLLDDL। सामान्य तौर पर, हम अपनी पसंद के अनुसार विभिन्न लंबाई के अंकों के क्रम को बदल सकते हैं, NrArrangementsसंभावनाओं की संख्या देता है। और जबकि अंकों के रनों के बीच एक अक्षर होना चाहिए, अन्य अक्षर निश्चित नहीं हैं। Binomialइन संभावनाओं गिना जाता है।

अब यह रन डिजिट की लंबाई होने के सभी संभावित तरीकों से चलता रहता है। rसभी अंकों की cकुल संख्याओं के pमाध्यम से , और अंकों के cसाथ सभी विभाजनों के माध्यम से चलाता है r

हमारे द्वारा देखे जाने वाले विभाजन की कुल संख्या विभाजन की संख्या से दो कम है n+1, और विभाजन कार्य जैसे बढ़ते हैं exp(sqrt(n))। इसलिए जबकि परिणामों को पुन: उपयोग करके (एक अलग क्रम में विभाजनों के माध्यम से) चल रहे समय में सुधार करने के लिए अभी भी आसान तरीके हैं, एक मौलिक सुधार के लिए हमें प्रत्येक विभाजन को अलग-अलग देखने से बचने की आवश्यकता है।

यह तेजी से कम्प्यूटिंग

ध्यान दें (p+q)@r = p@r + q@r। अपने दम पर, यह सिर्फ कुछ गुणा से बचने में मदद करता है। लेकिन इसके साथ-साथ (p+q)#r = p#r + q#rइसका मतलब है कि हम अलग-अलग विभाजनों के अनुरूप सरल जोड़ पॉलीओनॉमिक्स द्वारा जोड़ सकते हैं। हम उन सभी को नहीं जोड़ सकते हैं, क्योंकि हमें अभी भी यह जानना होगा कि lहमारे पास कौन-कौन से @-combine हैं, हमें किस कारक का उपयोग करना है, और कौन #-से-अभी भी संभव हैं।

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

यहाँ मेरा C ++ कोड है:

#include<vector>
#include<algorithm>
#include<iostream>
#include<gmpxx.h>

using bignum = mpz_class;
using poly = std::vector<bignum>;

poly mult(const poly &a, const poly &b){
  poly res ( a.size()+b.size()-1 );
  for(int i=0; i<a.size(); ++i)
    for(int j=0; j<b.size(); ++j)
      res[i+j]+=a[i]*b[j];
  return res;
}

poly extend(const poly &d, const poly &e, int ml, poly &a, int l, int m){
  poly res ( 26*ml+1 );
  for(int i=1; i<std::min<int>(1+26*ml,e.size()); ++i)
    for(int j=1; j<std::min<int>(1+26*ml/i,d.size()); ++j)
      res[i*j] += e[i]*d[j];
  for(int i=1; i<res.size(); ++i)
    res[i]=res[i]*l/m;
  if(a.empty())
    a = poly { res };
  else
    for(int i=1; i<a.size(); ++i)
      a[i]+=res[i];
  return res;
}

bignum f(int n){
  std::vector<poly> dp;
  poly digits (10,1);
  poly dd { 1 };
  dp.push_back( dd );
  for(int i=1; i<n; ++i){
    dd=mult(dd,digits);
    int l=1+26*(n-i);
    if(dd.size()>l)
      dd.resize(l);
    dp.push_back(dd);
  }

  std::vector<std::vector<poly>> a;
  a.reserve(n);

  a.push_back( std::vector<poly> { poly { 0, 1 } } );
  for(int i=1; i<n; ++i)
    a.push_back( std::vector<poly> (1+std::min(i,n+i-i)));
  for(int m=n-1; m>0; --m){
    //    std::cout << "m=" << m << "\n";
    for(int sum=n-m; sum>=0; --sum)
      for(int len=0; len<=std::min(sum,n+1-sum); ++len){
        poly d {a[sum][len]} ;
        if(!d.empty())
          for(int sumn=sum+m, lenn=len+1, e=1;
              sumn+lenn-1<=n;
              sumn+=m, ++lenn, ++e)
            d=extend(d,dp[m],n-sumn,a[sumn][lenn],lenn,e);
      }
  }
  poly let (27,1);
  let[0]=0;
  poly lp { 1 };
  bignum t { 0 };
  for(int sum=n-1; sum>0; --sum){
    lp=mult(lp,let);
    for(int len=1; len<=std::min(sum,n+1-sum); ++len){
      poly &a0 = a[sum][len];
      bignum s {0};
      for(int i=1; i<std::min(a0.size(),lp.size()); ++i)
        s+=a0[i]*lp[i];
      bignum bin;
      mpz_bin_uiui( bin.get_mpz_t(), n-sum+1, len );
      t+=bin*s;
    }
  }
  return t;
}

int main(){
  int n;
  std::cin >> n;
  std::cout << f(n) << "\n" ;
}

यह GNU MP लाइब्रेरी का उपयोग करता है। डेबियन पर, स्थापित करें libgmp-dev। के साथ संकलित करें g++ -std=c++11 -O3 -o pl pl.cpp -lgmp -lgmpxx। कार्यक्रम स्टड से अपना तर्क लेता है। समय के लिए, का उपयोग करें echo 100 | time ./pl

अंत में a[sum][length][i]जिन तरीकों की संख्या देता है sum में अंकों lengthरन नंबर दे सकते हैं i। गणना के दौरान, mलूप की शुरुआत में , यह उन तरीकों की संख्या देता है जो संख्या से अधिक के साथ किया जा सकता है m। यह सब के साथ शुरू होता है a[0][0][1]=1। ध्यान दें कि यह संख्याओं का एक सुपरसेट है जिसे हमें छोटे मानों के लिए फ़ंक्शन की गणना करने की आवश्यकता है। तो लगभग एक ही समय में, हम सभी मूल्यों की गणना कर सकते हैं n

कोई पुनरावृत्ति नहीं है, इसलिए हमारे पास निश्चित संख्या में नेस्टेड लूप हैं। (सबसे गहरा घोंसला स्तर 6. है।) प्रत्येक लूप कई मूल्यों से गुजरता nहै जो सबसे खराब स्थिति में रैखिक है । इसलिए हमें केवल बहुपद समय की आवश्यकता है। यदि हम नेस्टेड iऔर अंदर jछोरों को करीब से देखते हैं extend, तो हम jफॉर्म के लिए एक ऊपरी सीमा पाते हैं N/i। यह केवल jलूप के लिए एक लघुगणकीय कारक देना चाहिए । f ( sumnआदि के साथ ) अंतरतम पाश समान है। यह भी ध्यान रखें कि हम संख्याओं के साथ गणना करते हैं जो तेजी से बढ़ती हैं।

ध्यान दें कि हम O(n^3)इन नंबरों को स्टोर करते हैं।

प्रयोगात्मक रूप से, मुझे ये परिणाम उचित हार्डवेयर (i5-4590S) पर मिलते हैं: f(50)एक सेकंड और 23 एमबी, f(100)21 सेकंड और 166 एमबी की f(200)आवश्यकता होती है , 10 मिनट और 1.5 जीबी की f(300)आवश्यकता होती है , और एक घंटे और 5.6 जीबी की आवश्यकता होती है। यह एक समय जटिलता से बेहतर सुझाव देता है O(n^5)


जैसा कि यह एक कोड गोल्फ चुनौती है, इस उत्तर को गोल्फ बनाने की आवश्यकता है। माफ़ कीजिये।
R

1
@ रिकर जबकि मुझे नहीं लगता कि मेरा कोड शुरू होने के साथ ही शुरू हो गया था, मैंने कुछ और घूमा और व्हॉट्सएप के बाहर निचोड़ने पर इसके आकार को निर्धारित करने का भार उठाया।
क्रिश्चियन सेवर्स 16

1
@carusocomputing मुझे डर है कि यह बहुत बुरा है। मैं अंकों के रनों के बीच अंकों के वितरण के प्रत्येक मामले को अलग-अलग संभाल रहा हूं, जैसे कि तीन अंकों में से एक रन है, या दो अंकों में से एक रन और एक एकल अंक है, या तीन एकल अंक हैं, लेकिन इसके लिए n=5, कोई नहीं है दो अंकों की संख्या और दो एकल अंकों के साथ मामला, क्योंकि तब हमारे पास संख्याओं को अलग करने के लिए पर्याप्त पत्र नहीं होते हैं। यह वही है जो तीन बाहरी forछोरों करते हैं: संख्याओं के सभी उपयोगी विभाजन के माध्यम से चलाते हैं <n। (और मुझे एहसास हुआ कि मैं भी nअंकों की अनुमति देता हूं । किन्नर भाग्य से एक और अनुकूलन इसे 0 के रूप में गिनता है)।
क्रिश्चियन सेवर्स

1
@carusocomputing ध्यान दें कि संख्याओं के लिए <n/2, सभी विभाजन उपयोगी हैं। और शेष संगणनाएँ अभी भी अपना निरंतर समय लेती हैं। यह देखने के लिए कि क्या चल रहा है, आप लूप Print(p,"\n");के शरीर की शुरुआत में जोड़ सकते हैं for p...। - मुझे एक लूप कम उपयोग करने का विचार मिला, लेकिन यह केवल कोड आकार में मदद करेगा।
क्रिश्चियन सेवर्स

2
मैं mod(जो पहले से ही बहुत मदद की) को आगे बढ़ाते हुए Value, इसे बदलते हुए एक अद्भुत गति प्राप्त करता है Value(d mod x^(1+QuoInt(s(l)-1,i-1)),x^(i-1))। यह अकेले f(15)80 सेकंड में गणना करने की अनुमति देता है ।
क्रिश्चियन सिवर्स

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.