Plan zajęć dla grupy 424
Logika na bramkach:
SWB:
http://paste.ots.me/27489/text
maj 2025 P W Ś C P S N 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Kategorie
Plan zajęć dla grupy 424
Logika na bramkach:
SWB:
http://paste.ots.me/27489/text
Drugi projekt z ASD:
Rozważmy nieskierowany pełny graf ważony G=(V,E,w), gdzie V={v(0), v(1), …, v(n-1)} jest zbiorem wierzchołków grafu. Waga krawędzi w(i,j) łączącej pewne dwa wierzchołki grafu v(i) oraz v(j) jest równa
w(i,j)=((i+1)*(j+1)) mod p + 1,
gdzie p jest zadaną dodatnią liczbą naturalną. Dalej pajączkiem nazywamy acykliczny podzbiór krawędzi grafu Gpowstały zgodnie z następującym schematem:
Dalej zbiór S={s(0), s(1), …, s(k-1)} jest zbiorem pajączków. Ustal ostateczną liczbę krawędzi składowych oraz łączną sumę wag krawędzi składowych każdego z k pajączków przyjmując następujący schemat równoczesnej konstrukcji pajączków:
zakładając, że krawędź użyta przez dowolnego pajączka (tj. włączona do stosownego zbioru E’) nie może być ponownie użyta przez żadnego innego pajączka.
Kolejno:
Ciąg k wierszy postaci liczba naturalna x znak odstępu/spacji (ASCII kod 32) liczba naturalna y znak nowego wiersza/linii (ASCII kod 10), gdzie x jest ostateczną liczbą krawędzi składowych a y jest łączną sumą wag krawędzi składowych każdego kolejnego pajączka począwszy od s(0) do s(k-1) włącznie.
Koszt czasowy i pamięciowy rozwiązania ograniczony przez limity dostępnego czasu i dostępnej pamięci ustalone dla rozważanego zadania na automatycznej platformie sprawdzającej.
Wejście: 4 5 1 2 0 1 Wyjście: 3 8
Wejście: 5 7 2 2 0 2 1 4 Wyjście: 4 15 4 18
Rozwiązanie w Javie:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Scanner; import java.util.ArrayList; class Edge { short node_1 = 0; short node_2 = 0; int points = 0; Edge(short node_1, short node_2, int points) { this.node_1 = node_1; this.node_2 = node_2; this.points = points; } }; class EdgesSorter implements Comparator<Edge> { @Override public int compare(Edge edge_1, Edge edge_2) { if(edge_1.points != edge_2.points) { return edge_1.points - edge_2.points; } else { return edge_1.node_1 - edge_2.node_1; } } } class Spider { short id = 0; int points = 0; short edgesCount = 0; boolean[] nodes = null; short[] parentNode = null; Spider(short id) { this.id = id; nodes = new boolean[Main.nodesCount]; parentNode = new short[Main.nodesCount]; } } public class Main { static int nodesCount = 0; public static void main(String[] args) { Scanner scanner = new Scanner(new BufferedReader(new InputStreamReader(System.in))); nodesCount = scanner.nextInt(); int pNumber = scanner.nextInt(); short spidersCount = scanner.nextShort(); Spider[] spidersList = new Spider[spidersCount]; Spider[] sortedSpiders = new Spider[spidersCount]; short spiderNodesCount = 0; Spider spider = null; for(short spiderID = 0; spiderID < spidersCount; spiderID++) { spider = new Spider(spiderID); spidersList[spiderID] = spider; sortedSpiders[spiderID] = spider; spiderNodesCount = scanner.nextShort(); boolean[] nodes = new boolean[nodesCount]; while(spiderNodesCount-- > 0) { nodes[scanner.nextShort()] = true; } spider.nodes = nodes; short[] parentNode = new short[nodesCount]; for(short node = 0; node < nodesCount; node++) { parentNode[node] = node; } spider.parentNode = parentNode; } List<Edge> edgesList = new ArrayList<Edge>(); for(short node_1 = 1; node_1 <= nodesCount; node_1++) { for(short node_2 = (short) (node_1+1); node_2 <= nodesCount; node_2++) { edgesList.add(new Edge((short) (node_1 - 1), (short) (node_2 - 1), ((node_1 * node_2) % pNumber) + 1)); } } Collections.sort(edgesList, new EdgesSorter()); short topParent_1 = 0; short topParent_2 = 0; short activeSpidersCount = spidersCount; boolean deactiveSpider = true; short highestPrioritySpiderID = 0; short tmpNode = 0; while(activeSpidersCount > 0) { for(short activeSpiderID = 0; activeSpiderID < activeSpidersCount; activeSpiderID++) { spider = spidersList[activeSpiderID]; Spider mSpider = spidersList[highestPrioritySpiderID]; if(spider.points < mSpider.points || (spider.points == mSpider.points && spider.id < mSpider.id)) { highestPrioritySpiderID = activeSpiderID; } } spider = spidersList[highestPrioritySpiderID]; deactiveSpider = true; for(Edge edge : edgesList) { if(spider.nodes[edge.node_1] == true || spider.nodes[edge.node_2] == true) { tmpNode = edge.node_1; topParent_1 = spider.parentNode[tmpNode]; while(tmpNode != topParent_1) { tmpNode = topParent_1; topParent_1 = spider.parentNode[topParent_1]; } tmpNode = edge.node_2; topParent_2 = spider.parentNode[tmpNode]; while(tmpNode != topParent_2) { tmpNode = topParent_2; topParent_2 = spider.parentNode[topParent_2]; } if(topParent_1 != topParent_2) { spider.nodes[edge.node_1] = true; spider.nodes[edge.node_2] = true; spider.points += edge.points; spider.edgesCount++; spider.parentNode[topParent_1] = topParent_2; deactiveSpider = false; edgesList.remove(edge); break; } } } if(deactiveSpider) { spidersList[highestPrioritySpiderID] = spidersList[--activeSpidersCount]; } highestPrioritySpiderID = 0; } for(Spider sortedSpider : sortedSpiders) { System.out.println(sortedSpider.edgesCount + " " + sortedSpider.points); } } }
Pierwszy projekt z ASD:
Rozważmy zbiór P={p(0), p(1), …, p(n-1)} składający się z n społeczności lokalnych, dla których ustalona jest relacja bezpośredniego sąsiedztwa. Ze zbioru P wybieramy k róznych elementów, które będą stanowiły punkty startowe kampanii wyborczych k kandydatów q(0), q(1), …, q(k-1). Dalej proces realizacji kampanii wyborczych przebiega w turach tak, że:
i kończy się z chwilą, gdy wszystkie społeczności lokalne należące do zbioru P mają ustalone sztaby wyborcze kandydatów.
Ustal finansowanie kosztów kampanii wyborczej, w zależności od przyjętego wariantu rozstrzygania prawyborów (wariant A albo wariant B), dla każdego z k kandydatów, jeżeli koszty kampanii wyborczej mierzymy ostateczną liczbą założonych sztabów wyborczych w obrębie rozważanego zbioru społeczności lokalnych P.
Kolejno:
Ciąg k wierszy postaci liczba naturalna a znak odstępu/spacjii (ASCII kod 32) liczba naturalna b znak nowego wiersza/linii (ASCII kod 10), z których każdy reprezentuje kolejno koszt kampanii wyborczej w wariancie A (wartość a) i w wariancie B (wartość b) każdego kolejnego kandydata począwszy od kandydata q(0).
Złożoność czasowa O((n^2)k), złożoność pamięciowa O(n+m+k), gdzie n jest liczbą społeczności lokalnych, m jest rozmiarem relacji sąsiedztwa na zbiorze P, a k jest liczbą kandydatów. Fizyczny limit pamięci ograniczony przez 10 MB.
Wejście: 3 0 1 1 2 0 2 -1 -1 2 0 1 Wyjście: 1 2 2 1
Wejście: 6 1 0 2 1 3 0 3 1 3 2 4 2 4 3 5 0 5 2 -1 -1 3 0 1 5 Wyjście: 1 3 2 2 3 1
Rozwiązanie w C++:
#include<stdio.h> class Town; class Thief; class ListElementTown { public: Town* town; ListElementTown* next; ListElementTown(Town* m) { this->town = m; this->next = NULL; } ListElementTown(Town* m, ListElementTown* next) { this->town = m; this->next = next; } }; class ListTowns { public: ListElementTown* first; int elementsCounter; ListTowns() { first = NULL; elementsCounter = 0; } Town* get(int elementIterator) { ListElementTown* tmp = first; for(int i = 0; i < elementIterator; i++) tmp = tmp->next; return tmp->town; } void add(Town* m) { if(this->first == NULL) this->first = new ListElementTown(m); else first = new ListElementTown(m, first); elementsCounter++; } bool contains(Town* m) { ListElementTown* tmp = first; while(tmp) { if(m == tmp->town) return true; tmp = tmp->next; } return false; } void clear() { first = NULL; elementsCounter = 0; } }; class ListElementThief { public: Thief* thief; ListElementThief* next; ListElementThief(Thief* t) { this->thief = t; this->next = NULL; } ListElementThief(Thief* t, ListElementThief* next) { this->thief = t; this->next = next; } }; class ListThiefs { public: ListElementThief* first; int elementsCounter; ListThiefs() { first = NULL; elementsCounter = 0; } Thief* get(int elementIterator) { ListElementThief* tmp = first; for(int i = 0; i < elementIterator; i++) tmp = tmp->next; return tmp->thief; } void add(Thief* t) { if(this->first == NULL) this->first = new ListElementThief(t); else { first = new ListElementThief(t, first); } elementsCounter++; } bool contains(Thief* t) { ListElementThief* tmp = first; while(tmp) { if(t == tmp->thief) return true; tmp = tmp->next; } return false; } void clear() { first = NULL; elementsCounter = 0; } }; class Town { public: bool koniec; int id; Thief* electionStaffA; Thief* electionStaffB; Thief* tmpWinnerA; Thief* tmpWinnerB; ListThiefs* candidatesA; ListThiefs* candidatesB; ListTowns* neighbors; Town(int i) { koniec = false; id = i; electionStaffA = NULL; electionStaffB = NULL; tmpWinnerA = NULL; tmpWinnerB = NULL; candidatesA = new ListThiefs(); candidatesB = new ListThiefs(); neighbors = new ListTowns(); } }; class Thief { public: int id; int tmpCounterA; int tmpCounterB; int campaignCostA; int campaignCostB; Thief(int indeks) { this->id = indeks; this->tmpCounterA = 0; this->tmpCounterB = 0; this->campaignCostA = 0; this->campaignCostB = 0; } }; int main() { int workingElectionStaffCounterA = 0; int workingElectionStaffCounterB = 0; int liczba_miast = 0; int liczba_kandydatow = 0; fscanf(stdin, "%d", &liczba_miast); Town* towns[liczba_miast]; for(int i = 0; i < liczba_miast; i++) { towns[i] = new Town(i); } int towna; int townb; fscanf(stdin, "%d", &towna); fscanf(stdin, "%d", &townb); while(towna != -1 && townb != -1) { towns[towna]->neighbors->add(towns[townb]); towns[townb]->neighbors->add(towns[towna]); fscanf(stdin, "%d", &towna); fscanf(stdin, "%d", &townb); } fscanf(stdin, "%d", &liczba_kandydatow); Thief* candidates[liczba_kandydatow]; for(int i = 0; i < liczba_kandydatow; i++) { candidates[i] = new Thief(i); } int sztab; for(int i = 0; i < liczba_kandydatow; i++) { fscanf(stdin, "%d", &sztab); towns[sztab]->electionStaffA = candidates[i]; candidates[i]->campaignCostA++; workingElectionStaffCounterA++; towns[sztab]->electionStaffB = candidates[i]; candidates[i]->campaignCostB++; workingElectionStaffCounterB++; } ListTowns* modifiedTowns = new ListTowns(); while(workingElectionStaffCounterA != liczba_miast && workingElectionStaffCounterB != liczba_miast) { modifiedTowns->clear(); for(int i = 0; i < liczba_miast; i++) { if(towns[i]->electionStaffA != NULL && towns[i]->electionStaffB != NULL) { for(int i2 = 0; i2 < towns[i]->neighbors->elementsCounter; i2++) { if(towns[i]->neighbors->get(i2)->electionStaffA == NULL && towns[i]->neighbors->get(i2)->electionStaffB == NULL) { if(!(towns[i]->neighbors->get(i2)->candidatesA->contains(towns[i]->electionStaffA))) { towns[i]->neighbors->get(i2)->candidatesA->add(towns[i]->electionStaffA); } if(!(towns[i]->neighbors->get(i2)->candidatesB->contains(towns[i]->electionStaffB))) { towns[i]->neighbors->get(i2)->candidatesB->add(towns[i]->electionStaffB); } if(!(modifiedTowns->contains(towns[i]->neighbors->get(i2)))) { modifiedTowns->add(towns[i]->neighbors->get(i2)); } } } } } ListElementTown* startElement = modifiedTowns->first; int loopsCounter = modifiedTowns->elementsCounter; for(int i = 0; i < loopsCounter; i++) { Town* currentTown = startElement->town; Thief* tmpCandidate = NULL; for(int x = 0; x < liczba_kandydatow; x++) { candidates[x]->tmpCounterA = 0; candidates[x]->tmpCounterB = 0; } int loopsCounter_2 = currentTown->neighbors->elementsCounter; ListElementTown* neighborsLoop = currentTown->neighbors->first; for(int ii = 0; ii < loopsCounter_2; ii++) { Town* tmpTown = neighborsLoop->town; if(tmpTown->electionStaffA != NULL) { tmpTown->electionStaffA->tmpCounterA++; tmpTown->electionStaffB->tmpCounterB++; } neighborsLoop = neighborsLoop->next; } Thief* winnerA = currentTown->candidatesA->get(0); Thief* winnerB = currentTown->candidatesB->get(0); loopsCounter_2 = currentTown->candidatesA->elementsCounter; for(int i2 = 1; i2 < loopsCounter_2; i2++) { tmpCandidate = currentTown->candidatesA->get(i2); if((winnerA->tmpCounterA > tmpCandidate->tmpCounterA) || (winnerA->tmpCounterA == tmpCandidate->tmpCounterA && winnerA->id < tmpCandidate->id)) winnerA = tmpCandidate; } currentTown->tmpWinnerA = winnerA; currentTown->candidatesA->clear(); loopsCounter_2 = currentTown->candidatesB->elementsCounter; for(int i2 = 1; i2 < loopsCounter_2; i2++) { tmpCandidate = currentTown->candidatesB->get(i2); if((winnerB->tmpCounterB < tmpCandidate->tmpCounterB) || (winnerB->tmpCounterB == tmpCandidate->tmpCounterB && winnerB->id > tmpCandidate->id)) winnerB = tmpCandidate; } currentTown->tmpWinnerB = winnerB; currentTown->candidatesB->clear(); startElement = startElement->next; } startElement = modifiedTowns->first; loopsCounter = modifiedTowns->elementsCounter; for(int i = 0; i < loopsCounter; i++) { Town* tmpTown = startElement->town; tmpTown->electionStaffA = tmpTown->tmpWinnerA; tmpTown->electionStaffB = tmpTown->tmpWinnerB; tmpTown->electionStaffA->campaignCostA++; tmpTown->electionStaffB->campaignCostB++; workingElectionStaffCounterA++; workingElectionStaffCounterB++; startElement = startElement->next; } } for(int i = 0; i < liczba_kandydatow; i++) { fprintf(stdout, "%d %d\n",candidates[i]->campaignCostA,candidates[i]->campaignCostB); } return 0; }
Czwarte zadanie z ASD:
Rozważmy uporządkowany ciąg C różnych liczb naturalnych długości n>0 oraz wybrany element c tego ciągu. Dalej przyjmujemy, że algorytm wyszukiwania binarnego jest zgodny z poniższym (zakładamy indeksowanie elementów ciągu od wartości początkowej 0):
1 l:=0, r:=n-1, m:=(l+r)/2; 2 3 while (C[m]!=c) { 4 if (C[m]<c) 5 l:=m+1; 6 else 7 r:=m-1; 8 m:=(l+r)/2; 9 }
Wprowadzamy teraz modyfikacje algorytmu wyszukiwania binarnego polegającą na tym, że w miejsce instrukcji zawartych w wierszach 4-8 w pewnej iteracji rozważanego algorytmu wykonujemy sekwencyjne przeszukanie pozostałego fragmentu ciągu począwszy od pozycji l aż do skutku, tj.
4 while (C[l]!=c) 5 l:=l+1; 6 7 m:=l; 8
Załóżmy, że koszt wykonania algorytmu wszykiwania binarnego (zarówno bez i z w/w modyfikacją) oznaczamy jako COST i definiujemy zależnością:
COST=sqrt(a)*div+cmp
gdzie a jest pewną dodatnią stałą naturalną, sqrt(a) jest funkcją, której rezultatem jest część naturalna z pierwiastka z liczby a oraz div i cmp to odpowiednio liczba operacji dzielenia przez 2 (wiersze 1 i 8) oraz liczba operacji prówniania z elementami ciągu C występujacych w rozważanym algorytmie (wiersze 3 i 4).
Wyznacz najmniejszą możliwą wartość stałej a, dla której wykonanie algorytmu wyszukiwania binarnego z modyfikacją sekwencyjną niezależnie od wybranej iteracji zastosowania tej modyfikacji, prowadzi w każdym przypadku do rozwiązania o koszcie mniejszym niż standardowe wyszukiwanie binarne (tj. algorytm bez modyfikacji sekwencyjnej).
Wiersz zawierający ciąg liczb naturlanych oddzielonych znakiem odstępu/spacji (ASCII kod 32) i zakończony znakiem końca pliku (EOF), gdzie:
Wiersz zawierajacy pojedynczą liczbę naturalną nie większą niż 10^9 będącą rozwiązaniem postawionego problemu (wiersz pusty w przypadku braku rozwiązania).
Złożoność czasowa O(n), złożoność pamięciowa O(n), gdzie n jest długością ciągu podanego na wejściu. Fizyczny limit pamięci zależny od rozmiaru danych wejściowych i ograniczony przez 4n B + 1 KB.
Wejście: 3 1 2 3 3 Wyjście: 9
Wejście: 10 0 1 2 3 4 5 6 7 8 9 0 Wyjście: 1
Rozwiązanie w C++:
#include <stdio.h> int main() { int n; fscanf(stdin, "%i", &n); int* C = new int[n]; for(int i = 0; i < n; i++) { fscanf(stdin, "%i", &C[i]); } int c; fscanf(stdin, "%i", &c); n--; int l = 0; int r = n; int m = (l + r) / 2; int binarneDzielenie = 1; int binarnePorownania = 1; while(C[m] != c) { binarnePorownania++; if(C[m] < c) l = m + 1; else r = m - 1; binarnePorownania++; m = (l + r) / 2; binarneDzielenie++; } int indeksWyniku = m; l = 0; r = n; m = (l + r) / 2; int minimalneA = 0; int sekwencyjneDzielenie = 1; int sekwencyjnePorownania = 1; while(C[m] != c) { sekwencyjnePorownania++; int iloscPorownan = sekwencyjnePorownania + indeksWyniku - l + 1; int a = ((iloscPorownan - binarnePorownania) / (binarneDzielenie - sekwencyjneDzielenie)) + 1; if(a > minimalneA) minimalneA = a; if(C[m] < c) l = m + 1; else r = m - 1; sekwencyjnePorownania++; m = (l + r) / 2; sekwencyjneDzielenie++; } fprintf(stdout, "%i", minimalneA * minimalneA); return 0; }
Trzecie zadanie z ASD:
Rozważmy niepuste drzewo binarne T etykietowane literami alfabetu angielskiego (tylko małe litery) i zapisane wierzchołkowo tak, że pozycję dowolnego wierzchołka x w drzewie T określa ciąg skierowań krawędzi (L – lewa krawędź, P – prawa krawędź) jakie pokonamy przechodząc w drzewie T ścieżkę od korzenia do wierzchołka x (przykłady poniżej).
Wyznacz najstarsze leksykograficznie słowo, jakie można zbudować z etykiet wierzchołków występujących na dowolnej ścieżce wierzchołek zewnętrzny (liść) drzewa T, korzeń drzewa T.
Wejście
Ciąg wierszy zakończony symbolem znaku końca pliku (EOF) reprezentujący w sposób poprawny pewne drzewo binarne T. Każdy pojedynczy wiersz zakończony znakiem nowego wiersza/linii (ASCII kod 10) opisujący pozycję wierzchołka w drzewie T i zawierający:
małą literę alfabetu nagielskiego (ASCII kod od 97 do 122) – etykieta wirzchołka,
znak odstępu/spacji (ASCII kod 32),
ciąg znaków L (ASCII kod 76) oraz R (ASCII kod 82) – ciąg skierowań krawędzi.
Liczba wierzchołków drzwa T ograniczona zawarta w przedziale [1,10^6]. Wysokość drzewa T ograniczona przez 2^6.Wyjście
Wiersz zawierajacy ciąg znaków będący rozwiązaniem postawionego problemu.
Złożoności i limity
Złożoność czasowa O(nh), złożoność pamięciowa O(n) bez uwzględnienia kosztów mechanizmu rekursji, gdzie n jest liczbą wierzchołków drzewa T a h jest jego wysokością. Fizyczny limit pamięci, bez uwzględnienia kosztu mechanizmu rekursji, zależny od rozmiaru danych wejściowych i ograniczony przez 10n B+1 KB.
Przykład 1
Wejście:
a LL
d
a R
s LWyjście:
asd
Przykład 2Wejście:
s LR
o LRR
m RR
p LRLRL
k
w LRL
a LL
t L
h R
j LRLRWyjście:
pjwstk
Jedno z wielu możliwych rozwiązań:
#include<iostream> using namespace std; class Element { public: char value; Element* left; Element* right; Element() { value = NULL; left = NULL; right = NULL; } }; void showTree(Element* element) { if(element->left) showTree(element->left); if(element->right) showTree(element->right); cout << element->value; } char isOneNode(Element* element) { if(element->left && element->right) return 0; else if(element->left) return isOneNode(element->left); else if(element->right) return isOneNode(element->right); else return 1; } char getTheBest(Element* element) { char r1 = 0; char r2 = 0; if(!element->left && !element->right) { return element->value - 70; } else { if(element->left) { r1 = getTheBest(element->left); } if(element->right) { r2 = getTheBest(element->right); } } if(r1 != 0 && r1 < 90) { delete element->left; element->left = NULL; r1 = r1 + 70; } if(r2 != 0 && r2 < 90) { delete element->right; element->right = NULL; r2 = r2 + 70; } if(r1 > r2) { delete element->right; element->right = NULL; return r1; } else if(r1 < r2) { delete element->left; element->left = NULL; return r2; } return r2; } int main() { char lastChar; char tmpChar; Element* root = new Element(); Element* currentNode = root; cin >> lastChar; while(cin >> tmpChar) { if(tmpChar == 'L') { if(currentNode->left == NULL) { currentNode->left = new Element(); } currentNode = currentNode->left; } else if(tmpChar == 'R') { if(currentNode->right == NULL) { currentNode->right = new Element(); } currentNode = currentNode->right; } else { currentNode->value = lastChar; lastChar = tmpChar; currentNode = root; } } currentNode->value = lastChar; while(!isOneNode(root)) { cout << getTheBest(root); } showTree(root); return 0; }
Drugie zadanie z ASD:
Rozważmy dowolny indeksowany ciąg liczb naturlanych C, dla którego definiujemy pojęcie wskaźnika aktualnej pozycji POS. Dalej wprowadzamy dwie operacje na elementach tego ciągu:
R() – usunięcie elementu c ciągu o indeksie POS+1, następnie przesunięcie wskaźnika POS o c elementów w prawo,
X() – wstawienie tuż po (pozycja POS+1) elemencie c ciągu o indeksie POS elementu o wartości c-1, następnie przesunięcie wskaźnika POS o c elementów w prawo.
Wyznacz postać ciagu wejściowego C po t-krotnym wykonaniu schematu operacji R() i X():jeżeli elementu ciągu o indeksie POS jest liczbą:
parzystą, to wykonaj operację R(),
nieparzystą, to wykonaj operację X(),
przyjmując, że:początkowo wskaźnik POS wskazuje na pierwszy element ciągu wejściowego (jeżeli taki istnieje),
jeżeli zachodzi taka konieczność przesuwanie wskaźnika POS w prawo odbywaja się w sposób cykliczny względem elementów ciągu C.
WejścieWierszy zawiera kolejno:
liczbę definiująca krotność t powtórzeń schematu operacji R() i X() zakończoną znakiem odstępu/spacji (ASCII kod 32),
elementy ciągu oddzielone znakiem odstępu/spacji i zakończone znakiem końca pliku (EOF).
Długość początkowa ciągu C zawarta w przedziale [0,10^6]. Liczba t powtórzeń schamatu operacji R() i X() ograniczona przez 10^6. Zakres przesunięcia wskaźnika POS w prawo określony przedziałem [0,10^9].Wyjście
Wiersz zakończony znakiem nowego wiersza/linii (ASCII kod 10) zawierajacy ciąg liczb naturalnych będący rozwiązaniem postawionego problemu wypisany cyklicznie, jeżeli zachodzi taka konieczność, począwszy od elementu ciągu wynikowego znajdującego się na pozycji wskazywanej przez wskaźnik POS w kierunku w prawo. Elementy ciągu wynikowego oddzielone znakiem odstępu/spacji (ASCII kod 32).
Złożoności i limity
Złożoność czasowa O(tn), złożoność pamięciowa O(n), gdzie n jest długością początkową ciągu C, t krotnością powtórzeń schamatu operacji R() i X(). Fizyczny limit pamięci zależny od rozmiaru danych wejściowych i ograniczony przez 12(n+t) B + 1 KB.
Przykład 1
Wejście:
3 1 2 3
Wyjście:
0 0 3 1Przykład 2
Wejście:
8 5 1 2 3
Wyjście:
2 2
A tutaj kodzik w C++:
#include <stdio.h> #include <iostream> struct C { unsigned int c; C* next; C(unsigned int value) { c = value; next = NULL; } }; int main() { unsigned int rounds; fscanf(stdin, "%u", &rounds); if(!feof(stdin)) { unsigned int elements = 0; unsigned int tmp; fscanf(stdin, "%u", &tmp); C* first = new C(tmp); elements++; C* current = first; while(std::cin >> tmp) { current->next = new C(tmp); current = current->next; elements++; } current->next = first; current = first; for(int i = 0; i < rounds; i++) { if(elements == 0) break; unsigned int value; if(current->c & 1) { value = current->c; C* newC = new C(value-1); newC->next = current->next; current->next = newC; elements++; } else { value = current->next->c; C* toDelete = current->next; current->next = toDelete->next; delete toDelete; elements--; } if(elements > 0) { value = value % elements; for(int ii = 0; ii < value; ii++) { current = current->next; } } } if(elements > 0) { first = current; fprintf(stdout, "%u", current->c); current = current->next; while(first != current) { fprintf(stdout, " %u", current->c); current = current->next; } } } fprintf(stdout, "\n"); return 0; }
Rozwiązanie na 100%. Treść:
Rozważmy rodzinę C ciągów rekurencyjnych C{n}, gdzie n jest pewną liczbą naturalną, których elementy zawarte są w zbiorze liczb naturalnych. Dalej i-ty element ciągu C{n} zapisujemy jako C{n}(i) i definiujemy rekurencyjnie w następujący sposób:
- n, dla i=0,
- C{n}(i-1)/2, dla i>0 oraz C{n}(i-1) będącego liczbą parzystą,
- 3C{n}(i-1)+1, dla i>0 oraz C{n}(i-1) będącego liczbą nieparzystą.
Na przykład dla n=7 ciąg C{7} ma postać:
7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, …
Sprawdź, czy podany na wejściu ciąg liczba naturalnych jest prefiksem pewnego ciągu z rodziny C. Jeżeli odpowiedź jest twierdząca wypisz na wyjściu OK, w przeciwnym przypadku wypisz sufiks ciagu wejściowego, którego pierwszy element jest zarazem pierwszym elementem tego ciągu, ze względu na który ten że ciąg przstał być prefiksem pewnego ciagu z rodziny C (przykłady poniżej).
Wejście
Wiersz zawierający ciąg liczb naturlanych dodatniej długości i zakończony znakiem końca pliku (EOF). Długość ciągu ograniczona przez 10^9. Elementy ciągu oddzielone znakiem odstępu/spacji (ASCII kod 32) i zawarte w przedziale wartości [0,10^9].
Wyjście
Wiersz zawierajacy słowo OK jeżeli wejście spełnia kryteria założone w zadaniu. W przeciwnym przypadku wiersz zawierający stosowny sufiks ciągu wejściowego. Elementy ciągu oddzielone znakiem odstępu/spacji (ASCII kod 32).
Złożoności i limity
Złożoność czasowa O(n), złożoność pamięciowa O(1), gdzie n jest długością ciągu podanego na wejściu. Fizyczny limit pamięci niezależny od rozmiaru danych wejściowych i ograniczony przez 1 KB.
Przykład 1
Wejście: 64 32 16 8 4 2 1 4 2 1 4 Wyjście: OKPrzykład 2
Wejście: 7 22 11 34 17 52 26 13 30 20 10 5 17 8 4 1 Wyjście: 30 20 10 5 17 8 4 1
Rozwiązanie w C:
#include int main() { int current; int next; int validInput = 1; fscanf(stdin, "%i", ¤t); while(!feof(stdin)) { fscanf(stdin, "%i", &next); if(current & 1) { if(current != (next-1)/3) { validInput = 0; break; } } else if(current != next*2) { validInput = 0; break; } current = next; } if(validInput == 1) { fprintf(stdout, "OK"); } else { fprintf(stdout, "%i", next); while(!feof(stdin)) { fscanf(stdin, "%i", &next); fprintf(stdout, " %i", next); } } return 0; }
Nie było takie trudne co nie? 🙂
Gdyby ktoś nie pamiętał adresu do testowania kodu:
http://asd.spox.spoj.pl/
Najlepsze rozwiązanie to kod w C, używa najmniej pamięci i wykonuje się w 0.09 sec (wynik: 100%).
#include <stdio.h> int main() { unsigned int iloscDoWczytania; fscanf(stdin, "%u", &iloscDoWczytania); unsigned int podstawa; fscanf(stdin, "%u", &podstawa); unsigned int suma = 0; unsigned short int wczytany = 1; while(iloscDoWczytania-- > 0) { fscanf(stdin, "%hu", &wczytany); suma += wczytany; } unsigned int iloscZnakow = 1; if(podstawa == 0) { iloscZnakow = 0; } else if(podstawa == 1) { iloscZnakow = suma; } else { while(suma > podstawa) { iloscZnakow++; suma = suma / podstawa; } } fprintf(stdout, "%u", iloscZnakow); return 0; }
Inne (o dziwo – jak w kolejnych zadaniach będzie coś z tablicami to raczej PHP nie ma szans na wykonanie obliczeń w wymaganym czasie) dobre rozwiązanie to użycie PHP, wykonuje się w 0.68 sec. (wynik: 100%):
<?PHP $message = file_get_contents('php://stdin'); $d = explode(chr(0x20), $message); $iloscDoWczytania = $d[0]; $podstawa = $d[1]; $suma = 0; $idDoWczytania = 2; while($iloscDoWczytania-- > 0) { $suma += $d[$idDoWczytania++]; } $iloscZnakow = 1; if($podstawa == 0) { $iloscZnakow = 0; } else if($podstawa == 1) { $iloscZnakow = $suma; } else { while($suma > $podstawa) { $iloscZnakow++; $suma = (int) ($suma / $podstawa); } } echo $iloscZnakow;
Dla osób co liczyły na pisanie w Javie mam niestety smutną wiadomość: Java jest za wolna! Ostatni test (w którym jest podane ponad 65000 parametrów/liczb) wykonuje się ponad 2 sekundy i nie zalicza ostatniego testu (wynik: 80% [4 z 5 testów]).
import java.util.Scanner; public class Main { public static void main(String[] argumenty) { Scanner in = new Scanner(System.in); int iloscDoWczytania = in.nextInt(); int podstawa = in.nextInt(); int suma = 0; while(iloscDoWczytania-- > 0) { suma += in.nextInt(); } int iloscZnakow = 1; if(podstawa == 0) { iloscZnakow = 0; } else if(podstawa == 1) { iloscZnakow = suma; } else { while(suma > podstawa) { iloscZnakow++; suma = suma / podstawa; } } System.out.print(iloscZnakow); } }