diff --git a/_data/contests/37-PDP.yml b/_data/contests/37-PDP.yml index 2a066586..9c66b99e 100644 --- a/_data/contests/37-PDP.yml +++ b/_data/contests/37-PDP.yml @@ -52,10 +52,10 @@ cauldron: statement_pdf_url: "https://drive.google.com/file/d/1tFvY_3m4KCz4ldE3vyLLsidE-PYt1hQs/view" statement_md: true testcases_url: "" - solution: false - solution_author: "" - codes_in_git: false - solution_tags: [] + solution: true + solution_author: "Κωνσταντίνος Μποκής" + codes_in_git: true + solution_tags: [sorting, greedy] on_judge: false shroompath: @@ -64,10 +64,10 @@ shroompath: statement_pdf_url: "https://drive.google.com/file/d/1tFvY_3m4KCz4ldE3vyLLsidE-PYt1hQs/view" statement_md: true testcases_url: "" - solution: false - solution_author: "" - codes_in_git: false - solution_tags: [] + solution: true + solution_author: "Κωνσταντίνος Μποκής" + codes_in_git: true + solution_tags: [greedy, modulo, binary counting] on_judge: false mergegame: diff --git a/_includes/source_code/code/37-PDP/cauldron/TASK b/_includes/source_code/code/37-PDP/cauldron/TASK new file mode 100755 index 00000000..b9a5c5ce --- /dev/null +++ b/_includes/source_code/code/37-PDP/cauldron/TASK @@ -0,0 +1,41 @@ +TASK( + name = "cauldron", + test_count = 33, + files_dir = "testdata/37-PDP/cauldron/", + input_file = "cauldron.in", + output_file = "cauldron.out", + time_limit = 1, + mem_limit = 64, + solutions = [ + SOLUTION( + name = "cauldron_brute", + source = "cauldron_brute.cc", + passes_up_to = 9, + lang = "c++", + ), + SOLUTION( + name = "cauldron_brute_recurse", + source = "cauldron_brute_recurse.cc", + passes_up_to = 9, + lang = "c++", + ), + SOLUTION( + name = "cauldron_subtask2", + source = "cauldron_subtask2.cc", + passes_only = [3,8,10,11,12,13,14,15,17,19,23,27,31], + lang = "c++", + ), + SOLUTION( + name = "cauldron_subtask3", + source = "cauldron_subtask3.cc", + passes_only = [3,8,10,11,12,13,14,15,16,17,18,19,20,21,23,27,31], + lang = "c++", + ), + SOLUTION( + name = "cauldron_correct", + source = "cauldron_correct.cc", + passes_all, + lang = "c++", + ), + ] +) diff --git a/_includes/source_code/code/37-PDP/cauldron/cauldron_brute.cc b/_includes/source_code/code/37-PDP/cauldron/cauldron_brute.cc new file mode 100755 index 00000000..c5ceaf4e --- /dev/null +++ b/_includes/source_code/code/37-PDP/cauldron/cauldron_brute.cc @@ -0,0 +1,35 @@ +#include +#include +#include +using namespace std; + +typedef long long ll; + +int main(){ +#ifdef CONTEST + freopen("cauldron.in","r",stdin); + freopen("cauldron.out","w",stdout); +#endif + long t, N, K, c; + scanf("%ld%ld%ld%ld",&t,&N,&K,&c); + vector w(N); + ll ans = 0; + for(auto& x:w) + scanf("%ld",&x); + if(N<=20){ + for(long s=0,m=(1L<=w[i]){ + test += w[i] + c; + Krem -= w[i]; + } + } + test += Krem; + ans = max(ans,test); + } + } + printf("%lld\n",ans); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/cauldron/cauldron_brute_recurse.cc b/_includes/source_code/code/37-PDP/cauldron/cauldron_brute_recurse.cc new file mode 100755 index 00000000..b362adbd --- /dev/null +++ b/_includes/source_code/code/37-PDP/cauldron/cauldron_brute_recurse.cc @@ -0,0 +1,34 @@ +#include +#include +using namespace std; + +typedef long long ll; + +long t, N, K, c; +long w[20]; +ll ans; + +void calc(long Krem,int i,ll csum=0){//Krem=μαγικό νερο στο καζάνι, csum=κέρδος από τα c + if(i==N){ + ans = max(ans, K + csum); + return; + } + calc(Krem,i+1,csum);//αν δεν πάρουμε το i + if(Krem>=w[i])//έχουμε αρκετό μαγικό νερό; + calc(Krem-w[i],i+1,csum+c);//αν πάρουμε το i +} + +int main(){ +#ifdef CONTEST + freopen("cauldron.in","r",stdin); + freopen("cauldron.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&N,&K,&c); + if(t==1){ + for(int i=0;i +#include +#include +using namespace std; + +typedef long long ll; + +int main(){ +#ifdef CONTEST + freopen("cauldron.in","r",stdin); + freopen("cauldron.out","w",stdout); +#endif + long t, N, K, c; + scanf("%ld%ld%ld%ld",&t,&N,&K,&c); + vector w(N); + ll ans = K; + for(auto& x:w) + scanf("%ld",&x); + if(c>0){ + sort(w.begin(),w.end()); + long Krem = K;//πόσο μαγικό νερό παραμένει στο καζάνι + for(auto e:w){ + if(e<=Krem){ + ans += c; + Krem -= e; + } else break; + } + } + printf("%lld\n",ans); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask2.cc b/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask2.cc new file mode 100755 index 00000000..91ea5a09 --- /dev/null +++ b/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask2.cc @@ -0,0 +1,12 @@ +#include + +int main(){ +#ifdef CONTEST + freopen("cauldron.in","r",stdin); + freopen("cauldron.out","w",stdout); +#endif + long t, N, K, c; + scanf("%ld%ld%ld%ld",&t,&N,&K,&c); + printf("%ld\n",K); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask3.cc b/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask3.cc new file mode 100755 index 00000000..2f79a2f5 --- /dev/null +++ b/_includes/source_code/code/37-PDP/cauldron/cauldron_subtask3.cc @@ -0,0 +1,24 @@ +#include +#include +using namespace std; + +typedef long long ll; + +int main(){ +#ifdef CONTEST + freopen("cauldron.in","r",stdin); + freopen("cauldron.out","w",stdout); +#endif + long t, N, K, c, w0; + scanf("%ld%ld%ld%ld",&t,&N,&K,&c); + ll ans = K; + if(t==3){ + scanf("%ld",&w0);//διάβασε ποσότητα ζωμού ενός βάζου + if(c>0){ + long jars = min(K/w0,N); + ans += (ll)jars*c; + } + } + printf("%lld\n",ans); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/TASK b/_includes/source_code/code/37-PDP/shroompath/TASK new file mode 100755 index 00000000..7dbac26b --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/TASK @@ -0,0 +1,53 @@ +TASK( + name = "shroompath", + test_count = 37, + files_dir = "testdata/37-PDP/shroompath/", + input_file = "shroompath.in", + output_file = "shroompath.out", + time_limit = 1, + mem_limit = 64, + solutions = [ + SOLUTION( + name = "shroom_brute_recursion", + source = "shroom_brute1.cc", + passes_up_to = 10, + lang = "c++", + ), + SOLUTION( + name = "shroom_brute_loop", + source = "shroom_brute2.cc", + passes_up_to = 10, + lang = "c++", + ), + SOLUTION( + name = "shroom_only_a", + source = "shroom_only_a.cc", + passes_only = [1,3,5,8,9,11,12,13,14,15,16,17,25,29,30,31,35,36,37], + lang = "c++", + ), + SOLUTION( + name = "shroom_only_b", + source = "shroom_only_b.cc", + passes_only = [2,4,6,7,10,18,19,20,21,22,23,24,26,27,28,32,33,34], + lang = "c++", + ), + SOLUTION( + name = "shroom_solution1", + source = "shroom_solution1.cc", + passes_all, + lang = "c++", + ), + SOLUTION( + name = "shroom_solution2", + source = "shroom_solution2.cc", + passes_all, + lang = "c++", + ), + SOLUTION( + name = "shroom_solution3", + source = "shroom_solution3_math.cc", + passes_all, + lang = "c++", + ), + ] +) diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_brute1.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_brute1.cc new file mode 100755 index 00000000..196b8cf8 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_brute1.cc @@ -0,0 +1,47 @@ +#include +#include +#include +using namespace std; + +int t,S,X,Y; +long ans = 1000000013; +vector Z; + +const char shrooms[] = "ab";//επιτρεπτοί χαρακτήρες +void add_length_w(vector& str,int pos){ + //υπολόγισε όλους τους συνδυασμούς ξεκινώντας από τη θέση pos + if(pos == str.size()){//καλύφθηκε το επιθυμητό μήκος + Z.insert(Z.end(),str.begin(),str.end()); + return; + } + for(int i=0;shrooms[i]!=0;i++){ + str[pos] = shrooms[i]; + add_length_w(str,pos+1); + } +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%d%d%d%d",&t,&S,&X,&Y); + int A = (X>0) ? (S+X-1)/X : -1; + int B = (Y>0) ? (S+Y-1)/Y : -1; + for(int w=1;w<=max(A,B);w++){ + vector str(w); + add_length_w(str,0); + } + if(A>0){ + vector f(A,'a'); + long pos = search(Z.begin(), Z.end(), f.begin(), f.end()) - Z.begin(); + ans = min(ans,pos+A); + } + if(B>0){ + vector f(B,'b'); + long pos = search(Z.begin(), Z.end(), f.begin(), f.end()) - Z.begin(); + ans = min(ans,pos+B); + } + printf("%ld\n",ans); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_brute2.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_brute2.cc new file mode 100755 index 00000000..3a7e2ae9 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_brute2.cc @@ -0,0 +1,40 @@ +#include +#include +#include +using namespace std; + +int t,S,X,Y; +long ans = 1000000000; +vector Z; + +void add_length_w(int w){ + for(int i=0;i < (1<=0;j--) + Z.push_back((i & (1<0) ? (S+X-1)/X : -1; + int B = (Y>0) ? (S+Y-1)/Y : -1; + for(int w=1;w<=max(A,B);w++) + add_length_w(w); + + if(X>0){ + vector f(A,'a'); + long pos = search(Z.begin(), Z.end(), f.begin(), f.end()) - Z.begin(); + ans = min(ans,pos+A); + } + if(Y>0){ + vector f(B,'b'); + long pos = search(Z.begin(), Z.end(), f.begin(), f.end()) - Z.begin(); + ans = min(ans,pos+B); + } + + printf("%ld\n",ans); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_only_a.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_only_a.cc new file mode 100755 index 00000000..1f886b57 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_only_a.cc @@ -0,0 +1,26 @@ +#include + +typedef long long ll; +const ll mod = 1000000007; +long t,S,X,Y; + +long calc_a(int A){ + ll pow2 = 1;//2^0 + ll prev=0;//άθροισμα μανιταριών που προσπεράσαμε στα προηγούμενα μήκη + for(long i=1;;i++){ + pow2 = (pow2 * 2) % mod;//2^i + if(A<=2*i-1) return (prev + A) % mod; + prev = (prev + pow2*i) % mod; + } + return -1L; +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&S,&X,&Y); + if(X>0)printf("%ld\n",calc_a((S+X-1)/X)); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_only_b.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_only_b.cc new file mode 100755 index 00000000..22b5216d --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_only_b.cc @@ -0,0 +1,26 @@ +#include + +typedef long long ll; +const ll mod = 1000000007; +long t,S,X,Y; + +long calc_b(int B){ + ll pow2 = 1;//2^0 + ll prev=0;//άθροισμα μανιταριών που προσπεράσαμε στα προηγούμενα μήκη + for(long i=1;;i++){ + if(i==B) return (prev + pow2*i + 1) % mod; + pow2 = (pow2 * 2) % mod;//2^i + prev = (prev + pow2*i) % mod; + } + return -1L; +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&S,&X,&Y); + if(Y>0)printf("%ld\n",calc_b((S+Y-1)/Y)); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_solution1.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_solution1.cc new file mode 100755 index 00000000..07d1c184 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_solution1.cc @@ -0,0 +1,29 @@ +#include + +typedef long long ll; +const ll mod = 1000000007; +long t,S,X,Y,A,B; + +long calc(int A, int B){ + ll pow2 = 1; + ll prev=0;//σύνολο μανιταριων που προσπερασαμε + for(int i=1;;i++){//για όλα τα πλάτη απο 1 έως ... + if(A<=2*i-1) return (prev + A) % mod; + if(i == B) return (prev + pow2*i + 1) % mod; + pow2 = (pow2 * 2) % mod; + prev = (prev + pow2*i) % mod; + } + return -1L; +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&S,&X,&Y); + A = (X>0) ? (S+X-1)/X : mod; + B = (Y>0) ? (S+Y-1)/Y : mod; + printf("%ld\n",calc(A,B)); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_solution2.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_solution2.cc new file mode 100755 index 00000000..d15120f0 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_solution2.cc @@ -0,0 +1,42 @@ +#include + +typedef long long ll; +const ll mod = 1000000007; +long t,S,X,Y,A,B; + +long calc_a(long A){ + ll pow2 = 1, prev = 0; + for(long i=1;2*i-1=A) + return calc_a(A); + else + return calc_b(B); +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&S,&X,&Y); + printf("%ld\n",calc(S,X,Y)); + return 0; +} diff --git a/_includes/source_code/code/37-PDP/shroompath/shroom_solution3_math.cc b/_includes/source_code/code/37-PDP/shroompath/shroom_solution3_math.cc new file mode 100755 index 00000000..f2eab902 --- /dev/null +++ b/_includes/source_code/code/37-PDP/shroompath/shroom_solution3_math.cc @@ -0,0 +1,41 @@ +#include + +typedef long long ll; +const ll mod = 1000000007; +long t,S,X,Y,A,B; + +ll pow2(long a){ + if(a == 0)return 1; + ll z = pow2(a/2); + z = (z * z) % mod; + if(a&1) + z = (z * 2) % mod; + return z; +} + +ll f(long w){ return (pow2(w)*w)%mod; } + +ll p(long w){ return (pow2(w+1)*(w-1)+2) % mod; } + +long calc(int s,int x,int y){ + long A = x ? ((s+x-1)/x) : mod; + long B = y ? ((s+y-1)/y) : mod; + if(B*2-1>=A){ + return (p(A/2) + A)%mod; + }else{ + ll w = f(B); + //το w πρέπει να είναι άρτιος ώστε να μπορεί να διαιρεθεί με το 2 + if(w & 1)w+=mod;//αν w περιττός, μετέτρεψε το σε ισοδύναμο (ως προς mod) άρτιο + return (p(B-1) + w/2+1)%mod; + } +} + +int main(){ +#ifdef CONTEST + freopen("shroompath.in","r",stdin); + freopen("shroompath.out","w",stdout); +#endif + scanf("%ld%ld%ld%ld",&t,&S,&X,&Y); + printf("%ld\n",calc(S,X,Y)); + return 0; +} diff --git a/assets/37-b-shroompath-a.svg b/assets/37-b-shroompath-a.svg new file mode 100755 index 00000000..f6cc766b --- /dev/null +++ b/assets/37-b-shroompath-a.svg @@ -0,0 +1,343 @@ + + + + + pdp37-b2-1 + + + + + + image/svg+xml + + pdp37-b2-1 + + + + + + + α + + + β + + + αα + + ββ + + βα + + αβ + + + ααα + + ααβ + + αβα + + αββ + + βαα + + βαβ + + ββα + + βββ + + + diff --git a/assets/37-b-shroompath-b.svg b/assets/37-b-shroompath-b.svg new file mode 100755 index 00000000..b60b8352 --- /dev/null +++ b/assets/37-b-shroompath-b.svg @@ -0,0 +1,339 @@ + + + + + pdp37-b2-1 + + + + + + image/svg+xml + + pdp37-b2-1 + + + + + + + α + + + β + + + αα + + ββ + + βα + + αβ + + + ααα + + ααβ + + αβα + + αββ + + βαα + + βαβ + + ββα + + βββ + + + diff --git a/assets/37-b-shroompath-exp1.svg b/assets/37-b-shroompath-exp1.svg new file mode 100755 index 00000000..3fb1a0fa --- /dev/null +++ b/assets/37-b-shroompath-exp1.svg @@ -0,0 +1,326 @@ + + + + + pdp37-b2-1 + + + + + + image/svg+xml + + pdp37-b2-1 + + + + + + + + α + + β + + + + αα + + ββ + + βα + + αβ + + + + ααα + + ααβ + + αβα + + αββ + + βαα + + βαβ + + ββα + + βββ + + + + diff --git a/assets/37-b-shroompath-full.svg b/assets/37-b-shroompath-full.svg new file mode 100755 index 00000000..676d8dcf --- /dev/null +++ b/assets/37-b-shroompath-full.svg @@ -0,0 +1,439 @@ + + + + + pdp37-b2-1 + + + + + + image/svg+xml + + pdp37-b2-1 + + + + + + + + + + + + α + + + + + β + + + + + + + + + + + + αα + + + + ββ + + + + βα + + + + αβ + + + + + + + + + + + + ααα + + + ααβ + + + αβα + + + + αββ + + + + βαα + + + + + βαβ + + + + ββα + + + + βββ + + + + + + + + diff --git a/contests/_36-PDP/c-bureaucracy-solution.md b/contests/_36-PDP/c-bureaucracy-solution.md index 31739d59..6855f160 100755 --- a/contests/_36-PDP/c-bureaucracy-solution.md +++ b/contests/_36-PDP/c-bureaucracy-solution.md @@ -30,8 +30,8 @@ codename: bureaucracy [^1]: Η αφαίρεση των διπλότυπων δεν είναι απαραίτητη για τη λύση του προβλήματος αλλά ενδέχεται να μειώνει τα βήματα της δυαδικής αναζήτησης καθώς δεν θα ελέγξουμε πάνω από μια φορά καμία τιμή $$L_{limit}$$. ```c++ - std::sort(W.begin(), W.end()); - W.erase(std::unique(W.begin(), W.end()), W.end()); + std::sort(W.begin(), W.end()); + W.erase(std::unique(W.begin(), W.end()), W.end()); ``` **Μειώνοντας τον αριθμό των αρχικών κόμβων:** Αντί να δοκιμάσουμε αναζήτηση κατά πλάτος για ένα $$L_{limit}$$ από κάθε αρχικό κόμβο και να πρέπει να ενώσουμε τα αποτελέσματα των αναζητήσεων στο τέλος για να δούμε αν καταφέραμε να φτάσουμε σε όλους τους τελικούς κόμβους, μπορούμε @@ -41,10 +41,10 @@ codename: bureaucracy ![Παράδειγμα εκφώνησης με dummy κόμβο](/assets/36-c-bureaucracy-sample1dummy.svg){:width="320px"} ```c++ - for(long i=0,s; i +Παράδειγμα για μήκη 1,2,3 + + +Για κάθε γράμμα **α** ή **β** έχουμε ένα συγκεκριμένο βάρος ($$X$$ και $$Y$$ αντίστοιχα). Zητείται πότε θα έχουμε +συγκεντρώσει συνολικό βάρος μεγέθους τουλάχιστον $$S$$ ως άθροισμα συνεχόμενων *ίδιων* γραμμάτων **α** ή **β**. + +**Παρατήρηση 1:** εφόσον θέλουμε το βάρος $$S$$ να αποτελείται αποκλειστικά από ίδια γράμματα +(έστω $$A$$ γράμματα **α** ή $$B$$ γράμματα **β**), αρκεί να διαιρέσουμε το +βάρος $$S$$ με το βάρος $$X$$ ή $$Y$$ *στρογγυλοποιώντας προς τα πάνω*, για να υπολογίσουμε τα $$A$$ και $$B$$. +Στα μαθηματικά ο συμβολισμός για τη στρογγυλοποίηση προς τα πάνω είναι +$$A = \lceil S/X \rceil, B = \lceil S/Y \rceil$$. + +Στη ``c++`` γνωρίζουμε ότι η ακέραια διαίρεση αγνοεί τυχόν δεκαδικά ψηφία, οπότε για το $$A$$, +αρκεί να κάνουμε τον υπολογισμό $$ A = (S+X-1)/X$$ (δηλαδή αυξάνουμε τόσο το $$S$$, +ώστε να αυξήσει το πηλίκο αν και μόνο αν η διαίρεση +του $$S$$ με το $$X$$ δεν είναι τέλεια)[^1]. + +## Υποπρόβλημα 1 ($$ S\le 15 $$) + +Στο υποπρόβλημα αυτό θα χρειαστεί να εξερευνήσουμε τις συμβολοσειρές με μήκος $$1,2,\dots ,S$$, καθώς ο +πρώτος συνδυασμός συμβολοσειρών μήκους $$S$$ αποτελείται από $$S$$ **α** και ο τελευταίος από $$S$$ **β**. +Μάλιστα αν τα $$X$$ και $$Y$$ είναι μεγαλύτερα από $$1$$, θα καταφέρουμε να συγκεντρώσουμε +βάρος $$S$$ ακόμα πιο γρήγορα. +Ακολουθούν δύο τρόποι για να υπολογίσουμε όλους τους συνδυασμούς, με αναδρομή και με βρόγχο. + +**Αναδρομικά:** Βρίσκουμε όλους τους συνδυασμούς για κάθε μήκος συμβολοσειράς και τους προσθέσουμε σε έναν πίνακα +χαρακτήρων ``Z``. + +{% include code.md solution_name='shroom_brute1.cc' start=10 end=21 %} +Δείτε ολόκληρο τον κώδικα [εδώ]({% include link_to_source.md solution_name='shroom_brute1.cc' %}). + +Κατόπιν με τη χρήση της συνάρτησης ``search`` της βιβλιοθήκης ``algorithm`` βρίσκουμε την +πρώτη θέση που ξεκινούν τα $$A$$ συνεχόμενα **α** ή τα $$B$$ συνεχόμενα **β** που αναζητούμε. + +{% include code.md solution_name='shroom_brute1.cc' start=35 end=44 %} + +**Παρατήρηση 2:** Το πλήθος των συμβολοσειρών μήκους $$i$$ από τα δύο γράμματα, είναι $$2^i$$ (εφόσον κάθε θέση μπορεί να έχει +$$2$$ τιμές). Τα **α** και **β** μπορούν να θεωρηθούν ως οι αριθμοί $$0$$ και $$1$$ του δυαδικού συστήματος και η +παραγόμενη συμβολοσειρά να είναι η αλληλουχία όλων των μη μηδενικών φυσικών αριθμών απεικονισμένων στο δυαδικό σύστημα. + +**Με βρόγχο:** Χρησιμοποιώντας την *παρατήρηση 2*, μπορούμε να κατασκευάσουμε τις συμβολοσειρές με ένα βρόγχο ως εξής: + +{% include code.md solution_name='shroom_brute2.cc' start=10 end=14 %} + +Μπορείτε να βρείτε ολόκληρο τον κώδικα [εδώ]({% include link_to_source.md solution_name='shroom_brute2.cc' %}). +Η λύση με αναδρομή ή βρόγχο, χρειάζεται $$\mathcal{O}(S\cdot 2^S)$$ χρόνο. + +## Υποπρόβλημα 2 ($$ Χ\gt Y $$) + +Εφόσον οι χαρακτήρες τύπου **α** έχουν μεγαλύτερο βάρος, θα προλάβουμε να συγκεντρώσουμε το συνολικό βάρος $$S$$ με αυτά. +Τα μανιτάρια **β** δεν θα μας χρησιμεύσουν. + +**Παρατήρηση 3:** Για οποιοδήποτε μήκος $$w$$ συμβολοσειρών με $$w\gt 1$$, η πρώτη συμβολοσειρά αποτελείται από $$w$$ **α** και +η επόμενη από $$w-1$$ **α** και ένα **β**. Σε καμία άλλη θέση δεν έχουμε τόσα **α** συγκεντρωμένα. + +
+Μεγάλος συνδυασμός α +
+ +Γνωρίζοντας το πλήθος των συμβολοσειρών για κάποιο μήκος (*παρατήρηση 2*) και τη θέση που +βρίσκονται τα περισσότερα συγκεντρωμένα **α** (*παρατήρηση 3*), δεν χρειάζεται να κατασκευάσουμε +τις συμβολοσειρές παρά μόνο να υπολογίσουμε πόσοι χαρακτήρες υπήρξαν σε όλα τα προηγούμενα μήκη συνδυασμών +και σε ποιά θέση συγκεντρώσαμε τα απαραίτητα **α**. + +{% include code.md solution_name='shroom_only_a.cc' start=7 end=16 %} +Ο χρόνος που χρειάζεται αυτή η λύση είναι $$\mathcal{O}(S)$$. +Ολόκληρος ο κώδικας [εδώ]({% include link_to_source.md solution_name='shroom_only_a.cc' %}). + +## Υποπρόβλημα 3 ($$ Χ=0 $$) + +Στο υποπρόβλημα αυτό, τα **α** έχουν μηδενικό βάρος και δεν χρησιμεύουν. Παρατηρώντας την παρακάτω εικόνα είναι +φανερό ότι η μέγιστη συγκέντρωση από **β** βρίσκεται στο μέσο σχεδόν των συμβολοσειρών μήκους $$B$$. Πιο +συγκεκριμένα, οι πρώτες μισές συμβολοσειρές έχουν **α** στην πρώτη θέση και οι επόμενες μισές έχουν **β** στην πρώτη θέση. +Η τελευταία συμβολοσειρά με **α** πρώτο χαρακτήρα, έχει $$B-1$$ χαρακτήρες **β** να ακολουθούν και αμέσως +μετά ακολουθεί η πρώτη συμβολοσειρά με ένα **β** στην πρώτη θέση. Αυτή είναι και η θέση που καταφέρνουμε +να συγκεντρώσουμε τα $$B$$ **β**, δηλαδή μια θέση μετά τους μισούς χαρακτήρες των συνδυασμών μήκους $$B$$. + +
+Μεγάλος συνδυασμός β +
+ +{% include code.md solution_name='shroom_only_b.cc' start=7 end=16 %} +Ο χρόνος που χρειάζεται η λύση αυτή είναι $$\mathcal{O}(S)$$. +Ολόκληρος ο κώδικας [εδώ]({% include link_to_source.md solution_name='shroom_only_b.cc' %}). + +## Πλήρης λύση σε χρόνο $$\mathcal{O}(S)$$ + +Εφόσον γνωρίζουμε τις συγκεντρώσεις $$A$$ ή $$B$$ που χρειαζόμαστε για βάρος $$S$$, πρέπει να βρούμε μετά από πόσους +χαρακτήρες θα τις καταφέρουμε. Οι χαρακτήρες **α** και **β** όμως είναι τόσα πολλοί που +ξεπερνούν τα όρια των ακεραίων τύπων που παρέχει η ``c++`` και δεν μπορούμε να αποθηκεύσουμε +τις θέσεις που τα βρήκαμε παρά μόνο αν αποθηκεύσουμε τα υπόλοιπα των θέσεων με +κάποιον διαιρέτη όπως το $$10^9+7$$ που μας δίνει η εκφώνηση. +Η διάταξη των θέσεων έχει χαθεί από τη στιγμή που κρατάμε μόνο τα υπόλοιπα τους, +οπότε υπολογίζουμε προοδευτικά τους συνδυασμούς +**α** και **β** που συναντάμε και σταματάμε μόλις βρούμε την πρώτη λύση. + +{% include code.md solution_name='shroom_solution1.cc' start=7 end=17 %} +Ολόκληρος ο κώδικας [εδώ]({% include link_to_source.md solution_name='shroom_solution1.cc' %}). + +Αν όμως αξιοποιήσουμε την πληροφορία ότι τα $$B$$ μανιτάρια τύπου **β** τα συναντάμε στις συμβολοσειρές μήκους $$B$$, είναι +φανερό ότι μέχρι και $$2\cdot B-1$$ μανιτάρια τύπου **α** τα βρίσκουμε νωρίτερα από τα $$B$$ **β**. + +
+Όλοι οι συνδυασμοί +
+ +Ενώνοντας τις λύσεις των δύο προηγούμενων υποπροβλημάτων, έχουμε: + +{% include code.md solution_name='shroom_solution2.cc' start=25 end=32 %} +Ολόκληρος ο κώδικας [εδώ]({% include link_to_source.md solution_name='shroom_solution2.cc' %}). +Οι παραπάνω λύσεις χρειάζονται χρόνο $$\mathcal{O}(S)$$. + +## Πλήρης λύση σε χρόνο $$\mathcal{O}(\log_2{S})$$ + +Ο αριθμός των χαρακτήρων από όλους τους συνδυασμούς ενός μόνο πλάτους $$k$$, +δίνεται από τη συνάρτηση +$$f(k) = 2^k \cdot k$$. Ο υπολογισμός του συνόλου των μανιταριών μέχρι και το πλάτος $$k$$, δίνεται από +τη συνάρτηση $$p(k) = f(1)+f(2)+\dots+f(k)=\sum_{i=1}^{k}f(i) = \sum_{i=1}^{k} {i\cdot 2^i}$$.
+Η συνάρτηση αυτή μπορεί να υπολογισθεί με +$$p(k) = 2^{k+1}\cdot (k-1)+2$$ + +*Απόδειξη:* Θα χρησιμοποιήσουμε επαγωγή. Για $$k=1$$, έχουμε $$p(1) = 2^{1+1}\cdot (1-1) +2 = 2$$ το οποίο ισχύει (έχουμε $$2$$ χαρακτήρες, ένα **α** και ένα **β** στους συνδυασμούς με μήκος $$1$$).
+Έστω ότι ισχύει για κάποιο $$k$$, δηλαδή $$p(k) = 2^{k+1}\cdot (k-1)+2$$, θα αποδείξουμε ότι ισχύει και για το $$k+1$$, δηλαδή: + +$$p(k+1)=2^{(k+1)+1}\cdot ((k+1)-1)+2 =2^{k+2}\cdot k + 2.$$ + +Γνωρίζουμε ότι + +$$\begin{aligned} +p(k+1) &= p(k) + f(k+1)\\ +&=2^{k+1}\cdot (k-1)+2 + 2^{k+1} \cdot (k+1)\\ +&=2^{k+1}\cdot k - 2^{k+1} + 2 + 2^{k+1}\cdot k + 2^{k+1}\\ +&=2^{k+1}\cdot k - \cancel{2^{k+1}} + 2 + 2^{k+1}\cdot k + \cancel{2^{k+1}}\\ +&=2^{k+1}\cdot k + 2^{k+1}\cdot k + 2\\ +&=2\cdot 2^{k+1} \cdot k + 2\\ +&=2^{k+2}\cdot k +2 +\end{aligned}$$ + +άρα καταλήγουμε ότι ισχύει η $$p(k+1)$$, άρα η σχέση μας ισχύει για όλα τα $$k\ge1$$. + +Ο υπολογισμός της δύναμης με τη συνάρτηση ``pow2`` στην παραπάνω λύση, χρειάζεται +λογαριθμικό χρόνο ως προς τον εκθέτη (μέγιστος εκθέτης ο $$S$$), +οπότε ο χρόνος που χρειάζεται συνολικά η λύση είναι $$\mathcal{O}(\log_2{S})$$. +Ο σχετικός κώδικας ακολουθεί: +{% include code.md solution_name='shroom_solution3_math.cc' start=16 end=31 %} +Ολόκληρος ο κώδικας [εδώ]({% include link_to_source.md solution_name='shroom_solution3_math.cc' %}) + +[^1]: Υπάρχει και η συνάρτηση ``ceil`` στη ``c++`` που κάνει στρογγυλοποίηση προς τα πάνω. Βρίσκεται στη βιβλιοθήκη ``cmath``. +