Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <queue>
- #include <unordered_map>
- #include <unordered_set>
- #include <iostream>
- #include <fstream>
- #include <string>
- using namespace std;
- ////////////////////////////////////////////////////////////////
- //TYPES
- ///////////////////////////////////////////////////////////////
- //data
- struct Library;
- //logic
- class Scanner;
- //output
- struct LibOutput;
- using Output = std::unordered_map<int, LibOutput>;
- ////////////////////////////////////////////////////////////////
- //Functions
- ////////////////////////////////////////////////////////////////
- /*Median of all books scores*/
- double GetMedian();
- ////////////////////////////////////////////////////////////////
- //GLOBALS
- ////////////////////////////////////////////////////////////////
- //counters
- int g_DaysNum, g_BooksNum, g_LibrariesNum;
- //books
- struct
- {
- vector<int> Scores;
- //vector<vector<int>> Libraries;
- //vector<bool> ScannedFlags;
- } g_Books;
- #define SCORE(id) g_Books.Scores[id]
- //libraries
- vector<Library> g_Libraries;
- #define LIBRARY(id) g_Libraries[(id)]
- ////////////////////////////////////////////////////////////////
- //IMPLEMENTATIONS
- ////////////////////////////////////////////////////////////////
- struct BookScoreComp
- {
- bool operator()(int lbi, int rbi) const
- {
- const int lScore = SCORE(lbi);
- const int rScore = SCORE(rbi);
- if (lScore < rScore)
- return true;
- else if (lScore > rScore)
- return false;
- return lbi > rbi;
- }
- };
- struct LibOutput
- {
- vector<int> Books;
- void Write(std::ostream& out, int libId) const
- {
- out << libId << " " << Books.size() << endl;
- for (int bookId : Books)
- out << bookId << " ";
- out << endl;
- }
- };
- struct Library
- {
- Library(int id, vector<int>&& bookIds, int signUpDays, int booksPerDay)
- : Id(id)
- , BookIds(std::move(bookIds))
- , SignUpDays(signUpDays)
- , BooksPerDay(booksPerDay)
- {
- TotalScore = 0;
- for (int bookId : BookIds)
- TotalScore += SCORE(bookId);
- }
- const int Id;
- vector<int> BookIds;
- const int SignUpDays;
- const int BooksPerDay;
- long long TotalScore;
- inline int GetNextBookId() const { return GetRemainingBooksCount() > 0 ? BookIds[nextScanBookIdx] : -1; }
- inline int GetRemainingBooksCount() const { return BookIds.size() - nextScanBookIdx; }
- int GetExtendedBookScore(int remainingBooksToday) const
- {
- if (nextScanBookIdx + remainingBooksToday >= BookIds.size())
- return 0;
- return SCORE(BookIds[nextScanBookIdx + remainingBooksToday]);
- }
- inline int GetDailyScans() const
- {
- return std::min(GetRemainingBooksCount(), BooksPerDay);
- }
- void AdvanceBook(int bookId)
- {
- int bookIdx = nextScanBookIdx;
- while (BookIds[bookIdx] != bookId)
- ++bookIdx;
- std::swap(BookIds[bookIdx], BookIds[nextScanBookIdx]);
- if (nextScanBookIdx < BookIds.size())
- ++nextScanBookIdx;
- }
- private:
- int nextScanBookIdx = 0;
- };
- class Scanner
- {
- using LibScansMap = std::unordered_map<int, int>;
- using BookMap = std::unordered_map<int, vector<int>>;
- public:
- //Statistic methods
- inline bool IsNewBook(int bookId) const { return m_BookStates[bookId] == BookState::New; }
- inline bool IsPendingBook(int bookId) const { return m_BookStates[bookId] == BookState::Pending; }
- long long GetTotalBooksToday() const
- {
- long long totalBooks = 0;
- for (int libId : m_Libraries)
- {
- totalBooks += LIBRARY(libId).GetDailyScans();
- }
- return totalBooks;
- }
- double GetScansAverageToday() const
- {
- return (double)GetTotalBooksToday() / (double)m_Libraries.size();
- }
- public:
- Scanner() : m_BookStates(g_BooksNum, BookState::New) {};
- void DoOutput(ostream& outStream) const
- {
- size_t libsCount = std::count_if(m_Output.cbegin(), m_Output.cend(), [](Output::const_reference elem) {return !elem.second.Books.empty(); });
- outStream << libsCount << endl;
- for (int libId : m_Libraries)
- {
- auto& outputEntry = m_Output.at(libId);
- if (!outputEntry.Books.empty())
- outputEntry.Write(outStream, libId);
- }
- }
- void AddLibrary(int libraryId)
- {
- auto& library = LIBRARY(libraryId);
- InitLibrary(library);
- if (library.GetRemainingBooksCount() <= 0)
- return;
- m_Libraries.push_back(libraryId);
- const auto& books = library.BookIds;
- for (int bookId : books)
- {
- m_BookToLibraries[bookId].push_back(libraryId);
- m_BookStates[bookId] = BookState::Pending;
- }
- }
- void ScanBooks()
- {
- LibScansMap libraryScans;
- for (int libId : m_Libraries)
- {
- auto booksScans = LIBRARY(libId).GetDailyScans();
- if (booksScans > 0)
- libraryScans[libId] = booksScans;
- }
- while (!libraryScans.empty())
- {
- int optimalLibId = GetOptimalLibId(libraryScans);
- int bookId = LIBRARY(optimalLibId).GetNextBookId();
- m_Output[optimalLibId].Books.push_back(bookId);
- if (m_BookStates[bookId] == BookState::Scanned)
- {
- int nz = 0;
- }
- m_BookStates[bookId] = BookState::Scanned;
- for (int libId : m_BookToLibraries.at(bookId))
- {
- auto& library = LIBRARY(libId);
- library.AdvanceBook(bookId);
- auto it = libraryScans.find(libId);
- if (it != libraryScans.end())
- {
- it->second = std::min(it->second, library.GetRemainingBooksCount());
- if (--(it->second) <= 0)
- libraryScans.erase(it);
- }
- }
- }
- }
- private:
- int GetOptimalLibId(LibScansMap& remainingScans) const
- {
- auto optimalIt = remainingScans.end();
- int maxScore = INT_MIN;
- int minBonus = INT_MAX;
- int minId = g_LibrariesNum;
- for (auto it = remainingScans.begin(); it != remainingScans.end(); ++it)
- {
- auto& library = LIBRARY(it->first);
- int score = SCORE(library.GetNextBookId());
- int bonus = library.GetExtendedBookScore(it->second);
- int id = library.Id;
- if (score > maxScore || (score == maxScore && bonus < minBonus) || (score == maxScore && bonus == minBonus && id < minId))
- {
- optimalIt = it;
- maxScore = score;
- minBonus = bonus;
- minId = id;
- }
- }
- return optimalIt->first;
- }
- void InitLibrary(Library& library)
- {
- static BookScoreComp scoreComparator;
- auto newEnd = std::remove_if(library.BookIds.begin(), library.BookIds.end(), [this](int bookId) { return m_BookStates[bookId] == BookState::Scanned; });
- std::sort(library.BookIds.begin(), newEnd, [](int lbi, int rbi) { return scoreComparator(rbi, lbi); });
- library.BookIds.erase(newEnd, library.BookIds.end());
- }
- private:
- Output m_Output;
- BookMap m_BookToLibraries;
- std::vector<int> m_Libraries;
- enum class BookState
- {
- New,
- Pending,
- Scanned
- };
- std::vector<BookState> m_BookStates;
- };
- void DoInput(string& inputFile)
- {
- cin >> inputFile;
- ifstream in("test/" + inputFile + ".txt", ios::in);
- if (in.is_open() == false) {
- cout << "Couldn't open the file!" << endl;
- return;
- }
- in >> g_BooksNum;
- in >> g_LibrariesNum;
- in >> g_DaysNum;
- g_Books.Scores.resize(g_BooksNum);
- for (int& score : g_Books.Scores)
- {
- in >> score;
- }
- g_Libraries.reserve(g_LibrariesNum);
- for (size_t i = 0; i < g_LibrariesNum; i++)
- {
- int booksCount;
- in >> booksCount;
- int signUpDays;
- in >> signUpDays;
- int booksPerDay;
- in >> booksPerDay;
- vector<int> books(booksCount);
- for (int& bookId : books)
- in >> bookId;
- g_Libraries.emplace_back(i, std::move(books), signUpDays, booksPerDay);
- }
- in.close();
- }
- void DoOutput(const string& filename, const Scanner& scanner)
- {
- ofstream out("test/" + filename + ".out", ios::out);
- scanner.DoOutput(out);
- out.close();
- }
- double GetMedian()
- {
- static double median = -1;
- if (median < 0.0)
- {
- auto scores = g_Books.Scores;
- std::sort(scores.begin(), scores.end());
- const auto size = scores.size();
- if (size % 2 == 0)
- {
- auto mid = size / 2;
- median = ((double)(scores[mid] + scores[mid - 1])) / 2.0;
- }
- else
- {
- median = scores[size / 2];
- }
- }
- return median;
- }
- long long GetTotalScore()
- {
- static long long totalScore = -1;
- if (totalScore < 0)
- {
- for (int i = 0; i < g_BooksNum; ++i)
- totalScore += SCORE(i);
- }
- return totalScore;
- }
- #define USE_STATIC_SORT
- //#define USE_DYNAMIC_SHIT
- #if defined(USE_STATIC_SORT)
- double LibraryH(const Library& library)
- {
- //return (library.TotalScore * library.SignUpTime) / library.BooksPerDay;
- //return (((D - library.SignUpTime) * library.Books.size()) + library.BooksPerDay);
- /*return ((double)library.TotalScore
- * ((double)g_DaysNum - (double)library.BookIds.size() / (double)library.BooksPerDay + GetMedian()))
- / (double)library.SignUpDays;*/
- double possibleScore = 0, libIndex = 0;
- for (int i = 0; i < (g_DaysNum - library.SignUpDays) && libIndex < library.BookIds.size(); ++i)
- {
- for (int j = 0; j < library.BooksPerDay && libIndex < library.BookIds.size(); ++j)
- {
- possibleScore += SCORE(library.BookIds[libIndex]);
- ++libIndex;
- }
- }
- return (g_DaysNum - library.SignUpDays) * library.BooksPerDay * possibleScore;
- //return ((possibleScore + GetMedian()) * (g_DaysNum - (library.BookIds.size()) / library.BooksPerDay)) / library.SignUpDays;
- //return GetTotalScore()
- // - (g_BooksNum / library.BookIds.size()) + (possibleScore * (g_DaysNum - (library.BookIds.size()) / library.BooksPerDay)) / library.SignUpDays;
- //
- }
- int PickLibByStaticSort()
- {
- static bool shouldSort = true;
- static int nextIdx = 0;
- static vector<int> libraryIds;
- if (shouldSort)
- {
- shouldSort = false;
- for (int i = 0; i < g_LibrariesNum; ++i)
- libraryIds.push_back(i);
- //sort by heuristic
- std::sort(libraryIds.begin(), libraryIds.end(),
- [](int lhs, int rhs) {return LibraryH(LIBRARY(lhs)) > LibraryH(LIBRARY(rhs)); }
- );
- }
- return nextIdx < g_LibrariesNum ? libraryIds[nextIdx++] : -1;
- }
- #elif defined(USE_DYNAMIC_SHIT)
- /*Heuristic of a library, considering current scanning libraries and the current day*/
- double LibraryH(const Library& library, const Scanner& scanner, int today)
- {
- //return library.Id;
- static unordered_map<int, double> cachedResults;
- static int lastRefreshedDay = -1;
- if (today > lastRefreshedDay)
- cachedResults.clear();
- auto it = cachedResults.find(library.Id);
- if (it != cachedResults.end())
- return it->second;
- if (today + library.SignUpDays >= g_DaysNum)
- return 0.0;
- double jointScore = 0.0, disjointScore = 0.0;
- int jointCount = 0, disjointCount = 0;
- for (int bookId : library.BookIds)
- {
- if (scanner.IsNewBook(bookId))
- {
- disjointScore += SCORE(bookId);
- ++disjointCount;
- }
- else if (scanner.IsPendingBook(bookId))
- {
- jointScore += SCORE(bookId);
- ++jointCount;
- }
- }
- //jointScore /= (double)jointCount;
- //disjointScore /= (double)disjointCount;
- auto result = (double)library.BooksPerDay * (jointScore / (double)(library.SignUpDays*library.SignUpDays) + disjointScore / (double)library.SignUpDays);
- /*const double scansH = (scansMedian + scanner.GetScansAverageToday()) * 0.5 * (double)library.SignUpDays;
- const double scansW = 0.3;
- const double scansJointScoreEffect = 0.8;
- auto result = (double)library.BooksPerDay * (
- (pow(scansJointScoreEffect, scansH * scansW)) * (jointScore / (double)jointCount)
- + (disjointScore / (double)disjointCount)
- );*/
- cachedResults[library.Id] = result;
- return result;
- }
- int PickLibByDynamicState(const Scanner& scanner, int today)
- {
- static bool shouldInit = true;
- static list<int> remainingLibIds;
- if (shouldInit)
- {
- shouldInit = false;
- for (int i = 0; i < g_LibrariesNum; ++i)
- remainingLibIds.push_back(i);
- }
- if (remainingLibIds.empty())
- return -1;
- auto optimalIt = std::max_element(remainingLibIds.begin(), remainingLibIds.end(),
- [&](int lId, int rId)
- {
- return LibraryH(LIBRARY(lId), scanner, today) <
- LibraryH(LIBRARY(rId), scanner, today);
- }
- );
- int result = *optimalIt;
- remainingLibIds.erase(optimalIt);
- return result;
- }
- #endif
- int main()
- {
- //input
- string inputFile;
- DoInput(inputFile);
- Scanner scanner;
- int nextSignUpDay = 0;
- int libId = -1;
- //simulate days
- bool shouldSignUp = true;
- for (int day = 0; day < g_DaysNum; ++day)
- {
- if (day >= nextSignUpDay && libId != -1)
- {
- scanner.AddLibrary(libId);
- }
- if (shouldSignUp && day >= nextSignUpDay)
- {
- #if defined(USE_STATIC_SORT)
- libId = PickLibByStaticSort();
- #elif defined(USE_DYNAMIC_SHIT)
- libId = PickLibByDynamicState(scanner, day);
- #endif
- if (libId >= 0)
- {
- nextSignUpDay += LIBRARY(libId).SignUpDays;
- }
- else
- {
- shouldSignUp = false;
- }
- }
- scanner.ScanBooks();
- }
- //output
- DoOutput(inputFile, scanner);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement