@@ -0,0 +1,196 @@ | |||||
import java.io.*; | |||||
import java.lang.*; | |||||
import java.util.*; | |||||
class Edge { | |||||
public int s, a; | |||||
Edge(int s, int a) { | |||||
this.s = s; | |||||
this.a = a; | |||||
} | |||||
public String toString() { | |||||
return this.s + ", " + this.a; | |||||
} | |||||
} | |||||
class FSM { | |||||
private ArrayList<String> states, alpha, finalState, transitions, warnings; | |||||
private String initialState; | |||||
private Integer initialStateID; | |||||
private ArrayList<ArrayList<Edge>> tr; | |||||
private ArrayList<ArrayList<Edge>> tr2way; | |||||
private HashMap<String, Integer> stateToInt, alphaToInt; | |||||
private HashSet<Integer> isFinal; | |||||
private FileWriter out; | |||||
private Integer szs, sza; | |||||
private Boolean used[]; | |||||
public void error(String msg) throws IOException { | |||||
out.write("Error:\n" + msg); | |||||
out.close(); | |||||
System.exit(0); | |||||
} | |||||
int dfs(int v) { | |||||
int ans = 1, n = tr.get(v).size(); | |||||
used[v] = true; | |||||
for (int i = 0; i < n; ++i) { | |||||
int to = tr.get(v).get(i).s; | |||||
if (!used[to]) | |||||
ans += dfs(to); | |||||
} | |||||
return ans; | |||||
} | |||||
void dfs2way(int v) { | |||||
used[v] = true; | |||||
int n = tr2way.get(v).size(); | |||||
for (int i = 0; i < n; ++i) { | |||||
int to = tr2way.get(v).get(i).s; | |||||
if (!used[to]) | |||||
dfs2way(to); | |||||
} | |||||
} | |||||
FSM(String states, String alpha, String initialState, String finalState, String transitions, | |||||
FileWriter out) | |||||
throws IOException { | |||||
this.out = out; | |||||
if (!states.matches("states=\\[.*\\]$") || !alpha.matches("alpha=\\[.*\\]$") | |||||
|| !initialState.matches("init\\.st=\\[.*\\]$") | |||||
|| !finalState.matches("fin\\.st=\\[.*\\]$") || !transitions.matches("trans=\\[.*\\]$")) | |||||
error("E5: Input file is malformed"); | |||||
this.states = new ArrayList<String>(Arrays.asList(states.split("states=\\[|,|\\]"))); | |||||
this.alpha = new ArrayList<String>(Arrays.asList(alpha.split("alpha=\\[|,|\\]"))); | |||||
String[] temp = initialState.split("init\\.st=\\[|\\]"); | |||||
if (temp.length <= 1) | |||||
error("E4: Initial state is not defined"); | |||||
this.initialState = temp[1]; | |||||
this.finalState = | |||||
new ArrayList<String>(Arrays.asList(finalState.split("fin\\.st=\\[|,|\\]"))); | |||||
this.transitions = | |||||
new ArrayList<String>(Arrays.asList(transitions.split("trans=\\[|,|\\]"))); | |||||
this.szs = this.states.size(); | |||||
this.sza = this.alpha.size(); | |||||
stateToInt = new HashMap<String, Integer>(); | |||||
alphaToInt = new HashMap<String, Integer>(); | |||||
isFinal = new HashSet<Integer>(); | |||||
tr = new ArrayList<ArrayList<Edge>>(); | |||||
tr2way = new ArrayList<ArrayList<Edge>>(); | |||||
for (int i = 0; i < this.states.size(); ++i) { | |||||
tr.add(new ArrayList<Edge>()); | |||||
tr2way.add(new ArrayList<Edge>()); | |||||
} | |||||
warnings = new ArrayList<String>(); | |||||
used = new Boolean[szs]; | |||||
for (int i = 1; i < szs; ++i) this.stateToInt.put(this.states.get(i), i); | |||||
if (this.finalState.size() <= 1) | |||||
warnings.add("W1: Accepting state is not defined"); | |||||
for (int i = 1; i < this.finalState.size(); ++i) { | |||||
if (this.stateToInt.containsKey(this.finalState.get(i))) | |||||
isFinal.add(i); | |||||
else | |||||
error("E1: A state '" + this.finalState.get(i) + "' is not in the set of states"); | |||||
} | |||||
for (int i = 1; i < sza; ++i) alphaToInt.put(this.alpha.get(i), i); | |||||
for (int i = 1; i < this.transitions.size(); ++i) { | |||||
String[] cur = this.transitions.get(i).split(">"); | |||||
if (cur.length != 3) | |||||
error("E5: Input file is malformed"); | |||||
if (!this.stateToInt.containsKey(cur[0])) | |||||
error("E1: A state '" + cur[0] + "' is not in the set of states"); | |||||
if (!this.alphaToInt.containsKey(cur[1])) | |||||
error("E3: A transition '" + cur[1] + "' is not represented in the alphabet"); | |||||
if (!this.stateToInt.containsKey(cur[2])) | |||||
error("E1: A state '" + cur[2] + "' is not in the set of states"); | |||||
int l = stateToInt.get(cur[0]), m = alphaToInt.get(cur[1]), r = stateToInt.get(cur[2]); | |||||
tr.get(l).add(new Edge(r, m)); | |||||
tr2way.get(l).add(new Edge(r, m)); | |||||
tr2way.get(r).add(new Edge(l, m)); | |||||
} | |||||
if (stateToInt.containsKey(this.initialState)) | |||||
initialStateID = stateToInt.get(this.initialState); | |||||
else | |||||
error("E4: Initial state is not defined"); | |||||
int components = 0; | |||||
for (int i = 1; i < szs; ++i) used[i] = false; | |||||
for (int i = 1; i < szs; ++i) { | |||||
if (!used[i]) { | |||||
dfs2way(i); | |||||
components++; | |||||
} | |||||
} | |||||
if (components > 1) | |||||
error("E2: Some states are disjoint"); | |||||
for (int i = 1; i < szs; ++i) used[i] = false; | |||||
int cnt = dfs(initialStateID); | |||||
if (cnt != szs - 1) | |||||
warnings.add("W2: Some states are not reachable from the initial state"); | |||||
Boolean isDet = true, isComplete = true; | |||||
for (int i = 1; i < szs; ++i) { | |||||
HashSet<Integer> st = new HashSet<Integer>(); | |||||
for (int j = 0; j < tr.get(i).size(); ++j) { | |||||
int a = tr.get(i).get(j).a; | |||||
if (st.contains(a)) | |||||
isDet = false; | |||||
else | |||||
st.add(a); | |||||
} | |||||
if (st.size() != this.alpha.size() - 1) | |||||
isComplete = false; | |||||
} | |||||
if (!isDet) | |||||
warnings.add("W3: FSA is nondeterministic"); | |||||
if (isComplete) | |||||
out.write("FSA is complete"); | |||||
else | |||||
out.write("FSA is incomplete"); | |||||
if (warnings.size() > 0) | |||||
out.write("\nWarning: "); | |||||
for (int i = 0; i < warnings.size(); ++i) { | |||||
out.write("\n" + warnings.get(i)); | |||||
} | |||||
out.close(); | |||||
} | |||||
} | |||||
public class FSA { | |||||
public static void main(String[] args) throws IOException { | |||||
FileReader inp = new FileReader("fsa.txt"); | |||||
FileWriter out = new FileWriter("result.txt"); | |||||
Scanner in = new Scanner(inp); | |||||
String states = in.nextLine(); | |||||
String alpha = in.nextLine(); | |||||
String initialState = in.nextLine(); | |||||
String finalState = in.nextLine(); | |||||
String transitions = in.nextLine(); | |||||
FSM fsm = new FSM(states, alpha, initialState, finalState, transitions, out); | |||||
} | |||||
} |
@@ -0,0 +1,257 @@ | |||||
import java.io.*; | |||||
import java.lang.*; | |||||
import java.util.*; | |||||
class Edge { | |||||
public int s, a; | |||||
Edge(int s, int a) { | |||||
this.s = s; | |||||
this.a = a; | |||||
} | |||||
public String toString() { | |||||
return this.s + ", " + this.a; | |||||
} | |||||
} | |||||
class FSM { | |||||
private ArrayList<String> states, alpha, finalState, transitions; | |||||
private String initialState; | |||||
private Integer initialStateID; | |||||
private ArrayList<ArrayList<Edge>> tr; | |||||
private ArrayList<ArrayList<Edge>> tr2way; | |||||
private HashMap<String, Integer> stateToInt, alphaToInt; | |||||
private HashSet<Integer> isFinal; | |||||
private FileWriter out; | |||||
private Integer szs, sza; | |||||
private Boolean used[]; | |||||
private ArrayList<ArrayList<ArrayList<String>>> r; | |||||
public void error(String msg) throws IOException { | |||||
out.write("Error:\n" + msg); | |||||
out.close(); | |||||
System.exit(0); | |||||
} | |||||
int dfs(int v) { | |||||
int ans = 1, n = tr.get(v).size(); | |||||
used[v] = true; | |||||
for (int i = 0; i < n; ++i) { | |||||
int to = tr.get(v).get(i).s; | |||||
if (!used[to]) | |||||
ans += dfs(to); | |||||
} | |||||
return ans; | |||||
} | |||||
void dfs2way(int v) { | |||||
used[v] = true; | |||||
int n = tr2way.get(v).size(); | |||||
for (int i = 0; i < n; ++i) { | |||||
int to = tr2way.get(v).get(i).s; | |||||
if (!used[to]) | |||||
dfs2way(to); | |||||
} | |||||
} | |||||
FSM(String states, String alpha, String initialState, String finalState, String transitions, | |||||
FileWriter out) | |||||
throws IOException { | |||||
this.out = out; | |||||
// validate input | |||||
if (!states.matches("states=\\[.*\\]$") || !alpha.matches("alpha=\\[.*\\]$") | |||||
|| !initialState.matches("initial=\\[.*\\]$") | |||||
|| !finalState.matches("accepting=\\[.*\\]$") | |||||
|| !transitions.matches("trans=\\[.*\\]$")) | |||||
error("E0: Input file is malformed"); | |||||
this.states = new ArrayList<String>(Arrays.asList(states.split("states=\\[|,|\\]"))); | |||||
this.alpha = new ArrayList<String>(Arrays.asList(alpha.split("alpha=\\[|,|\\]"))); | |||||
this.finalState = | |||||
new ArrayList<String>(Arrays.asList(finalState.split("accepting=\\[|,|\\]"))); | |||||
this.transitions = | |||||
new ArrayList<String>(Arrays.asList(transitions.split("trans=\\[|,|\\]"))); | |||||
// initialization | |||||
this.szs = this.states.size() - 1; | |||||
this.sza = this.alpha.size() - 1; | |||||
if (szs <= 0 || sza <= 0) { | |||||
error("E0: Input file is malformed"); | |||||
} | |||||
stateToInt = new HashMap<String, Integer>(); | |||||
alphaToInt = new HashMap<String, Integer>(); | |||||
isFinal = new HashSet<Integer>(); | |||||
tr = new ArrayList<ArrayList<Edge>>(); | |||||
tr2way = new ArrayList<ArrayList<Edge>>(); | |||||
for (int i = 0; i < szs; ++i) { | |||||
tr.add(new ArrayList<Edge>()); | |||||
tr2way.add(new ArrayList<Edge>()); | |||||
} | |||||
used = new Boolean[szs]; | |||||
// initialize R[k][i][j]; 0 <= k <= n; 0 <= i, j < n; | |||||
r = new ArrayList<ArrayList<ArrayList<String>>>(); | |||||
for (int k = 0; k < szs + 1; k++) { | |||||
r.add(new ArrayList<ArrayList<String>>()); | |||||
for (int i = 0; i < szs; ++i) { | |||||
r.get(k).add(new ArrayList<String>()); | |||||
for (int j = 0; j < szs; ++j) { | |||||
r.get(k).get(i).add(new String()); | |||||
} | |||||
} | |||||
} | |||||
// create a graph with nodes starting from 0 | |||||
for (int i = 1; i <= szs; ++i) this.stateToInt.put(this.states.get(i), i - 1); | |||||
// validate transitions | |||||
for (int i = 1; i < this.transitions.size(); ++i) { | |||||
String[] cur = this.transitions.get(i).split(">"); | |||||
if (cur.length != 3) | |||||
error("E0: Input file is malformed"); | |||||
} | |||||
for (int i = 1; i < this.finalState.size(); ++i) { | |||||
if (this.stateToInt.containsKey(this.finalState.get(i))) | |||||
isFinal.add(this.stateToInt.get(this.finalState.get(i))); | |||||
else | |||||
error("E1: A state '" + this.finalState.get(i) + "' is not in the set of states"); | |||||
} | |||||
for (int i = 1; i <= sza; ++i) alphaToInt.put(this.alpha.get(i), i - 1); | |||||
for (int i = 1; i < this.transitions.size(); ++i) { | |||||
String[] cur = this.transitions.get(i).split(">"); | |||||
if (cur.length != 3) | |||||
error("E0: Input file is malformed"); | |||||
if (!this.stateToInt.containsKey(cur[0])) | |||||
error("E1: A state '" + cur[0] + "' is not in the set of states"); | |||||
if (!this.stateToInt.containsKey(cur[2])) | |||||
error("E1: A state '" + cur[2] + "' is not in the set of states"); | |||||
if (!this.alphaToInt.containsKey(cur[1])) | |||||
error("E3: A transition '" + cur[1] + "' is not represented in the alphabet"); | |||||
int l = stateToInt.get(cur[0]), m = alphaToInt.get(cur[1]), r = stateToInt.get(cur[2]); | |||||
tr.get(l).add(new Edge(r, m)); | |||||
tr2way.get(l).add(new Edge(r, m)); | |||||
tr2way.get(r).add(new Edge(l, m)); | |||||
} | |||||
int components = 0; | |||||
for (int i = 0; i < szs; ++i) used[i] = false; | |||||
for (int i = 0; i < szs; ++i) { | |||||
if (!used[i]) { | |||||
dfs2way(i); | |||||
components++; | |||||
} | |||||
} | |||||
if (components > 1) | |||||
error("E2: Some states are disjoint"); | |||||
for (int i = 0; i < szs; ++i) used[i] = false; | |||||
String[] temp = initialState.split("initial=\\[|\\]"); | |||||
if (temp.length <= 1) | |||||
error("E4: Initial state is not defined"); | |||||
this.initialState = temp[1]; | |||||
if (stateToInt.containsKey(this.initialState)) | |||||
initialStateID = stateToInt.get(this.initialState); | |||||
else | |||||
error("E1: A state '" + this.initialState + "' is not in the set of states"); | |||||
Boolean isDet = true, isComplete = true; | |||||
for (int i = 0; i < szs; ++i) { | |||||
HashSet<Integer> st = new HashSet<Integer>(); | |||||
for (int j = 0; j < tr.get(i).size(); ++j) { | |||||
int a = tr.get(i).get(j).a; | |||||
if (st.contains(a)) | |||||
isDet = false; | |||||
else | |||||
st.add(a); | |||||
} | |||||
if (st.size() != sza) | |||||
isComplete = false; | |||||
} | |||||
if (!isDet) | |||||
error("E5: FSA is nondeterministic"); | |||||
for (int i = 0; i < szs; ++i) { | |||||
for (int j = 0; j < tr.get(i).size(); ++j) { | |||||
String curAlpha; | |||||
int cur = tr.get(i).get(j).s; | |||||
if (r.get(0).get(i).get(cur).isEmpty()) | |||||
curAlpha = this.alpha.get(tr.get(i).get(j).a + 1); | |||||
else | |||||
curAlpha = r.get(0).get(i).get(cur) + "|" + this.alpha.get(tr.get(i).get(j).a + 1); | |||||
r.get(0).get(i).set(cur, curAlpha); | |||||
} | |||||
for (int j = 0; j < szs; ++j) { | |||||
if (i == j) { | |||||
String curAlpha; | |||||
if (r.get(0).get(i).get(j).isEmpty()) | |||||
curAlpha = "eps"; | |||||
else | |||||
curAlpha = r.get(0).get(i).get(j) + "|eps"; | |||||
r.get(0).get(i).set(j, curAlpha); | |||||
} else if (r.get(0).get(i).get(j).isEmpty()) { | |||||
String curAlpha = "{}"; | |||||
r.get(0).get(i).set(j, curAlpha); | |||||
} | |||||
} | |||||
} | |||||
for (int k = 1; k <= szs; ++k) { | |||||
for (int i = 0; i < szs; ++i) { | |||||
for (int j = 0; j < szs; ++j) { | |||||
String cur = "(" + r.get(k-1).get(i).get(k-1) + ")(" + r.get(k-1).get(k-1).get(k-1) + ")*(" + r.get(k-1).get(k-1).get(j) + ")|(" + r.get(k-1).get(i).get(j) + ")"; | |||||
r.get(k).get(i).set(j, cur); | |||||
} | |||||
} | |||||
} | |||||
String ans = new String(); | |||||
for (int i = 0; i < szs; ++i) { | |||||
if (isFinal.contains(i)) { | |||||
if(ans.isEmpty()) | |||||
ans = r.get(szs).get(initialStateID).get(i); | |||||
else | |||||
ans = ans + "|" + r.get(szs).get(initialStateID).get(i); | |||||
} | |||||
} | |||||
if(ans.isEmpty()) | |||||
ans = "{}"; | |||||
out.write(ans); | |||||
out.close(); | |||||
} | |||||
} | |||||
public class FSAtoREGEX { | |||||
public static void main(String[] args) throws IOException { | |||||
FileReader inp = new FileReader("input.txt"); | |||||
FileWriter out = new FileWriter("output.txt"); | |||||
Scanner in = new Scanner(inp); | |||||
String states = in.nextLine(); | |||||
String alpha = in.nextLine(); | |||||
String initialState = in.nextLine(); | |||||
String finalState = in.nextLine(); | |||||
String transitions = in.nextLine(); | |||||
FSM fsm = new FSM(states, alpha, initialState, finalState, transitions, out); | |||||
} | |||||
} |
@@ -0,0 +1,6 @@ | |||||
main: main.cpp | |||||
$(CXX) -g -o main -std=c++17 main.cpp | |||||
tester: tester.cpp | |||||
$(CXX) -g -o tester -std=c++17 tester.cpp | |||||
./tester > test.txt |
@@ -0,0 +1,632 @@ | |||||
#include <chrono> | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <memory> | |||||
#include <sstream> | |||||
#include <string> | |||||
#include <unordered_map> | |||||
/* | |||||
* Amirlan Sharipov BS21-01 | |||||
* https://codeforces.com/profile/RinRi | |||||
* I've copied most of the comments in this code from the assignment | |||||
* specification | |||||
*/ | |||||
#define PRIMENUM1 1000007 | |||||
#define PRIMENUM2 1003337 | |||||
#define MAXN 50001 | |||||
#define MINN 8 | |||||
using std::chrono::duration; | |||||
using std::chrono::duration_cast; | |||||
using std::chrono::high_resolution_clock; | |||||
using std::chrono::milliseconds; | |||||
template <class T> | |||||
class ICircularBoundedQueue { | |||||
public: | |||||
virtual void offer(const T &value) = 0; // insert an element to the rear of | |||||
// the queue overwrite the oldest | |||||
// elements when the queue is full | |||||
virtual T &poll() = 0; // remove an element from the front of the queue | |||||
virtual T &peek() const = 0; // look at the element at the front of the | |||||
// queue (without removing it) | |||||
virtual void flush() = 0; // remove all elements from the queue | |||||
virtual bool isEmpty() const = 0; // is the queue empty? | |||||
virtual bool isFull() const = 0; // is the queue full? | |||||
virtual int size() const = 0; // number of elements | |||||
virtual int capacity() const = 0; // maximum capacity | |||||
}; | |||||
template <class T> | |||||
class ArrayCircularBoundedQueue : ICircularBoundedQueue<T> { | |||||
public: | |||||
ArrayCircularBoundedQueue<T>(int maxSize) { | |||||
mxsz = maxSize; | |||||
data = new T *[mxsz](); | |||||
} | |||||
~ArrayCircularBoundedQueue<T>() { | |||||
for (int i = 0; i < mxsz; ++i) delete data[i]; | |||||
delete[] data; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
void offer(const T &value) { | |||||
if (sz < mxsz) { | |||||
curPush = (cur + sz) % mxsz; | |||||
sz++; | |||||
} | |||||
data[curPush++] = new T(value); | |||||
curPush %= mxsz; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
void offer(T *value) { | |||||
if (sz < mxsz) { | |||||
curPush = (cur + sz) % mxsz; | |||||
sz++; | |||||
} | |||||
data[curPush++] = value; | |||||
curPush %= mxsz; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
T &poll() try { | |||||
if (sz == 0) throw "queue is empty!"; | |||||
// T &ans = *data[cur]; | |||||
delete data[cur]; | |||||
data[cur] = NULL; | |||||
sz--; | |||||
cur++; | |||||
cur %= mxsz; | |||||
// return ans; | |||||
} catch (const char *msg) { | |||||
std::cerr << msg << std::endl; | |||||
throw; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
T *pollpoint() try { | |||||
if (sz == 0) throw "queue is empty!"; | |||||
// T &ans = *data[cur]; | |||||
data[cur] = NULL; | |||||
sz--; | |||||
cur++; | |||||
cur %= mxsz; | |||||
// return ans; | |||||
} catch (const char *msg) { | |||||
std::cerr << msg << std::endl; | |||||
throw; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
T &peek() const { return *data[cur]; } | |||||
T *peekpoint() const { return data[cur]; } | |||||
// time complexity: O(n) in any case | |||||
void flush() { | |||||
while (sz) poll(); | |||||
} | |||||
// time complexity: O(1) in any case | |||||
bool isEmpty() const { return !sz; } | |||||
// time complexity: O(1) in any case | |||||
bool isFull() const { return (sz == mxsz); } | |||||
// time complexity: O(1) in any case | |||||
int size() const { return sz; } | |||||
// time complexity: O(1) in any case | |||||
int capacity() const { return mxsz; } | |||||
// time complexity: O(n) in any case | |||||
void print() { | |||||
for (int i = 0; i < sz; ++i) { | |||||
// data[(cur + i) % mxsz].list(); | |||||
std::cout << *data[(cur + i) % mxsz] << '\n'; | |||||
} | |||||
} | |||||
void printset() { | |||||
for (int i = 0; i < sz; ++i) { | |||||
data[(cur + i) % mxsz]->list(); | |||||
std::cout << '\n'; | |||||
} | |||||
} | |||||
private: | |||||
T **data; | |||||
int sz = 0, mxsz = 0, cur = 0, curPush = 0; | |||||
}; | |||||
template <class T> | |||||
class IBoundedStack { | |||||
public: | |||||
virtual void push(const T &value) = 0; // push an element onto the stack | |||||
// remove the oldest element | |||||
// when if stack is full | |||||
virtual T &pop() = 0; // remove an element from the top of the stack | |||||
virtual T &top() const = 0; // look at the element at the top of the stack | |||||
// (without removing it) | |||||
virtual void flush() = 0; // remove all elements from the stack | |||||
virtual bool isEmpty() const = 0; // is the stack empty? | |||||
virtual bool isFull() const = 0; // is the stack full? | |||||
virtual int size() const = 0; // number of elements | |||||
virtual int capacity() const = 0; // maximum capacity | |||||
}; | |||||
template <class T> | |||||
class QueuedBoundedStack : IBoundedStack<T> { | |||||
public: | |||||
QueuedBoundedStack<T>(int size) { | |||||
q1 = new ArrayCircularBoundedQueue<T>(size); | |||||
q2 = new ArrayCircularBoundedQueue<T>(size); | |||||
mxsz = size; | |||||
} | |||||
~QueuedBoundedStack<T>() { | |||||
delete q1; | |||||
delete q2; | |||||
} | |||||
// time complexity: O(n*m), Theta(n*m). The algorithm's complexity depends | |||||
// on the size of q1 as well as the cost of operation of copying. In this | |||||
// case(problem C) it is O(n*m), that is why I decided to use pointers | |||||
// instead. See function below this one. Worst case O(n), best case O(1), | |||||
// avg O(n) | |||||
void push(const T &value) { | |||||
q2->offer(value); | |||||
while (!q1->isEmpty()) { | |||||
if (sz == mxsz && q1->size() == 1) { | |||||
q1->poll(); | |||||
break; | |||||
} | |||||
T &temp = q1->peek(); | |||||
q2->offer(temp); | |||||
q1->poll(); | |||||
} | |||||
if (sz < mxsz) sz++; | |||||
ArrayCircularBoundedQueue<T> *temp = q1; | |||||
q1 = q2; | |||||
q2 = temp; | |||||
} | |||||
// time complexity: O(n) | |||||
void push(T *value) { | |||||
q2->offer(value); | |||||
while (!q1->isEmpty()) { | |||||
if (sz == mxsz && q1->size() == 1) { | |||||
q1->poll(); | |||||
break; | |||||
} | |||||
T *temp = q1->peekpoint(); | |||||
q2->offer(temp); | |||||
q1->pollpoint(); | |||||
} | |||||
if (sz < mxsz) sz++; | |||||
ArrayCircularBoundedQueue<T> *temp = q1; | |||||
q1 = q2; | |||||
q2 = temp; | |||||
} | |||||
// time complexity: O(1) in any case (theta(1)) | |||||
T &pop() try { | |||||
if (q1->isEmpty()) throw "q1 is empty!"; | |||||
// T &ans = q1->peek(); | |||||
q1->poll(); | |||||
sz--; | |||||
// return ans; | |||||
} catch (const char *msg) { | |||||
std::cerr << msg << std::endl; | |||||
throw; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
T &top() const try { | |||||
if (q1->isEmpty()) throw "q1 is empty!"; | |||||
return q1->peek(); | |||||
} catch (const char *msg) { | |||||
std::cerr << msg << std::endl; | |||||
throw; | |||||
} | |||||
// time complexity: O(1) in any case | |||||
void flush() { | |||||
sz = 0; | |||||
q1->flush(); | |||||
q2->flush(); | |||||
} | |||||
// time complexity: O(1) in any case | |||||
bool isEmpty() const { return !sz; } | |||||
// time complexity: O(1) in any case | |||||
bool isFull() const { return (sz == mxsz); } | |||||
// time complexity: O(1) in any case | |||||
int size() const { return sz; } | |||||
// time complexity: O(1) in any case | |||||
int capacity() const { return mxsz; } | |||||
void print() { q1->print(); } | |||||
void printset() { q1->printset(); } | |||||
private: | |||||
ArrayCircularBoundedQueue<T> *q1, *q2; | |||||
int sz = 0, mxsz = 0, cur = 0, curPush = 0; | |||||
}; | |||||
template <class T> | |||||
class ISet { | |||||
virtual void add(const T &item) = 0; // add an item to the set | |||||
virtual void remove(T &item) = 0; // remove an item from the set | |||||
virtual bool contains( | |||||
T &item) const = 0; // check if an item belongs to the set | |||||
virtual int size() const = 0; // the number of elements in the set | |||||
virtual bool isEmpty() const = 0; // check if the set is empty | |||||
}; | |||||
template <class T> | |||||
class DoubleHashSet : ISet<T> { | |||||
public: | |||||
// TODO: Write comments about every method | |||||
enum State : char { EMPTY = 0, DELETED = 1, TAKEN = 2 }; | |||||
DoubleHashSet<T>() { | |||||
sz = 0; | |||||
mxsz = 0; | |||||
data = 0; | |||||
state = 0; | |||||
} | |||||
DoubleHashSet<T>(int maxSize) { | |||||
mxsz = maxSize; | |||||
sz = 0; | |||||
data = new T *[mxsz](); | |||||
state = new State[mxsz](); | |||||
} | |||||
// O(n) because of copying | |||||
DoubleHashSet<T>(const DoubleHashSet<T> &st) { | |||||
sz = st.size(); | |||||
mxsz = st.getMaxSize(); | |||||
data = new T *[mxsz](); | |||||
state = new State[mxsz](); | |||||
T **tempdata = st.getData(); | |||||
State *tempstate = st.getState(); | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
if (tempstate[i] == TAKEN) data[i] = new T(*tempdata[i]); | |||||
state[i] = tempstate[i]; | |||||
} | |||||
} | |||||
// O(n*m) deleting | |||||
~DoubleHashSet<T>() { | |||||
for (int i = 0; i < mxsz; ++i) | |||||
if (state[i] == TAKEN) delete data[i]; | |||||
delete[] data; | |||||
delete[] state; | |||||
} | |||||
// O(n*m) n -> size, m -> size of data | |||||
void list() { | |||||
std::ios_base::sync_with_stdio(0); | |||||
std::cin.tie(0); | |||||
std::cout.tie(0); | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
if (state[i] == TAKEN) std::cout << *data[i] << ' '; | |||||
} | |||||
} | |||||
// Compression function. O(1) | |||||
int hash(int h1, int h2, int64_t i) const { | |||||
// size_t h1 = hasher(item); | |||||
// h1 %= PRIMENUM1; | |||||
// size_t h2 = hasher(item); | |||||
// h2 %= PRIMENUM2; | |||||
return ((int64_t)h1 + i * (int64_t)h2) % (int64_t)mxsz; | |||||
// return ((int64_t)hash1(item, PRIMENUM1) + i * (int64_t)hash2(item, | |||||
// PRIMENUM2)) % mxsz; return (h1 + i * (int64_t)hash2(item, PRIMENUM2)) | |||||
// % mxsz; | |||||
} | |||||
// Hash function n1. O(n) | |||||
int hash1(const std::string &item, int prime) const { | |||||
int ans = 0, sz = item.size(); | |||||
int64_t cur = 1; | |||||
for (int i = 0; i < item.size(); ++i) { | |||||
ans += (cur * (int64_t)item[i]) % prime; | |||||
ans %= prime; | |||||
cur *= 127; | |||||
cur %= prime; | |||||
} | |||||
return ans; | |||||
} | |||||
// Hash function n2. O(n) | |||||
int hash2(const std::string &item, int prime) const { | |||||
int ans = 0, sz = item.size(); | |||||
int64_t cur = 1; | |||||
for (int i = 0; i < item.size(); ++i) { | |||||
ans += (cur * (int64_t)item[sz - i - 1]) % prime; | |||||
ans %= prime; | |||||
cur *= 127; | |||||
cur %= prime; | |||||
} | |||||
return ans; | |||||
} | |||||
// Add an item to the set O(n^2) in worst case (all colisions). Copying | |||||
// takes time as well. Avg and best case: O(n) | |||||
void add(const T &item) { | |||||
int h1 = hash1(item, PRIMENUM1), h2 = hash2(item, PRIMENUM2); | |||||
while (1) { | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
int pos = hash(h1, h2, i); | |||||
if (state[pos] == EMPTY || state[pos] == DELETED) { | |||||
data[pos] = new T(item); | |||||
state[pos] = TAKEN; | |||||
sz++; | |||||
return; | |||||
} else if (state[pos] == TAKEN) { | |||||
if (*data[pos] == item) return; | |||||
} | |||||
} | |||||
int tempmxsz = mxsz; | |||||
T **tempdata = data; | |||||
State *tempstate = state; | |||||
int newsz = std::max(2 * tempmxsz, 8); | |||||
data = new T *[newsz](); | |||||
state = new State[newsz](); | |||||
mxsz = newsz; | |||||
sz = 0; | |||||
for (int i = 0; i < tempmxsz; ++i) { | |||||
if (tempstate[i] == TAKEN) { | |||||
add(*tempdata[i]); | |||||
} | |||||
} | |||||
for (int i = 0; i < tempmxsz; ++i) | |||||
if (state[i] == TAKEN) delete tempdata[i]; | |||||
delete[] tempdata; | |||||
delete[] tempstate; | |||||
} | |||||
} | |||||
// Remove an item. worst case: O(n*m), avg and best: O(m), where m is size | |||||
// of data. | |||||
void remove(T &item) try { | |||||
int h1 = hash1(item, PRIMENUM1), h2 = hash2(item, PRIMENUM2); | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
int pos = hash(h1, h2, i); | |||||
if (state[pos] == EMPTY) break; | |||||
if (state[pos] == TAKEN) { | |||||
if (*data[pos] == item) { | |||||
delete data[pos]; | |||||
data[pos] = NULL; | |||||
state[pos] = DELETED; | |||||
sz--; | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
throw "specified item doesn't exist!"; | |||||
} catch (const char *msg) { | |||||
std::cerr << msg << std::endl; | |||||
throw; | |||||
} | |||||
// worst case: O(n) | |||||
bool contains(T &item) const { | |||||
int h1 = hash1(item, PRIMENUM1), h2 = hash2(item, PRIMENUM2); | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
int pos = hash(h1, h2, i); | |||||
if (state[pos] == EMPTY) break; | |||||
if (state[pos] == TAKEN) | |||||
if (*data[pos] == item) return true; | |||||
} | |||||
return false; | |||||
} | |||||
int size() const { return sz; } | |||||
bool isEmpty() const { return (sz == 0); } | |||||
T **getData() const { return data; } | |||||
State *getState() const { return state; } | |||||
int getMaxSize() const { return mxsz; } | |||||
// worst, avg, best case: O(n*m) | |||||
void operator=(const DoubleHashSet<T> &temp) { | |||||
for (int i = 0; i < mxsz; ++i) | |||||
if (state[i] == TAKEN) delete data[i]; | |||||
delete[] data; | |||||
delete[] state; | |||||
sz = temp.size(); | |||||
mxsz = temp.getMaxSize(); | |||||
data = new T *[mxsz](); | |||||
state = new State[mxsz](); | |||||
T **tempdata = temp.getData(); | |||||
State *tempstate = temp.getState(); | |||||
for (int i = 0; i < mxsz; ++i) { | |||||
if (tempstate[i] == TAKEN) data[i] = new T(*tempdata[i]); | |||||
state[i] = tempstate[i]; | |||||
} | |||||
} | |||||
private: | |||||
int mxsz = 0, sz = 0; | |||||
T **data; | |||||
State *state; | |||||
}; | |||||
void solveBoundedCommandQueue() { | |||||
int n, k; | |||||
std::cin >> n >> k; | |||||
std::cin.ignore(); | |||||
std::string s; | |||||
ArrayCircularBoundedQueue<std::string> q(k); | |||||
for (int i = 0; i < n; ++i) { | |||||
getline(std::cin, s); | |||||
if (q.size() == k) q.poll(); | |||||
q.offer(s); | |||||
} | |||||
q.print(); | |||||
} | |||||
void solveCMDWithoutRollbacks() { | |||||
std::ios_base::sync_with_stdio(false); | |||||
std::cin.tie(0); | |||||
std::cout.tie(0); | |||||
int n; | |||||
std::cin >> n; | |||||
std::cin.ignore(); | |||||
DoubleHashSet<std::string> files; | |||||
for (int i = 0; i < n; ++i) { | |||||
std::string cmd, cmdName, fileName; | |||||
getline(std::cin, cmd); | |||||
std::stringstream s(cmd); | |||||
s >> cmdName; | |||||
if (cmdName == "LIST") { | |||||
// TODO improve LIST command | |||||
files.list(); | |||||
std::cout << '\n'; | |||||
} else if (cmdName == "NEW") { | |||||
s >> fileName; | |||||
bool exists = files.contains(fileName); | |||||
if (exists) { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
} else { | |||||
files.add(fileName); | |||||
} | |||||
} else { | |||||
s >> fileName; | |||||
bool exists = files.contains(fileName); | |||||
if (exists) { | |||||
files.remove(fileName); | |||||
} else { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void solveCMDWithRollbacks() { | |||||
std::ios_base::sync_with_stdio(0); | |||||
std::cin.tie(0); | |||||
std::cout.tie(0); | |||||
int n, k; | |||||
std::cin >> n >> k; | |||||
std::cin.ignore(); | |||||
QueuedBoundedStack<DoubleHashSet<std::string>> states(k); | |||||
DoubleHashSet<std::string> dummy; | |||||
states.push(dummy); | |||||
for (int i = 0; i < n; ++i) { | |||||
std::string cmd, cmdName, fileName; | |||||
getline(std::cin, cmd); | |||||
std::stringstream s(cmd); | |||||
s >> cmdName; | |||||
if (cmdName == "LIST") { | |||||
// TODO improve LIST command | |||||
states.top().list(); | |||||
std::cout << '\n'; | |||||
} else if (cmdName == "NEW") { | |||||
// auto t1 = high_resolution_clock::now(); | |||||
DoubleHashSet<std::string> *files = | |||||
new DoubleHashSet<std::string>(states.top()); | |||||
s >> fileName; | |||||
bool exists = files->contains(fileName); | |||||
std::string similar = (fileName.back() == '/' | |||||
? fileName.substr(0, fileName.size() - 1) | |||||
: fileName + "/"); | |||||
bool existsSimilar = files->contains(similar); | |||||
if (exists || existsSimilar) { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
delete files; | |||||
} else { | |||||
files->add(fileName); | |||||
states.push(files); | |||||
// auto t2 = high_resolution_clock::now(); | |||||
// auto ms_int = duration_cast<milliseconds>(t2 - t1); | |||||
// std::cout << ms_int.count() << "ms\n"; | |||||
continue; | |||||
} | |||||
} else if (cmdName == "REMOVE") { | |||||
DoubleHashSet<std::string> *files = | |||||
new DoubleHashSet<std::string>(states.top()); | |||||
s >> fileName; | |||||
bool exists = files->contains(fileName); | |||||
if (exists) { | |||||
files->remove(fileName); | |||||
states.push(files); | |||||
continue; | |||||
} else { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
delete files; | |||||
} | |||||
} else if (cmdName == "UNDO") { | |||||
int times = 1; | |||||
if (cmd != "UNDO") s >> times; | |||||
if (states.size() > times) { | |||||
while (times--) { | |||||
states.pop(); | |||||
} | |||||
} else { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
} | |||||
} else { | |||||
std::cout << "ERROR: cannot execute " << cmd << '\n'; | |||||
} | |||||
} | |||||
} | |||||
int main() { | |||||
// solveBoundedCommandQueue(); | |||||
// solveCMDWithoutRollbacks(); | |||||
solveCMDWithRollbacks(); | |||||
} | |||||
@@ -0,0 +1,13 @@ | |||||
#include <iostream> | |||||
using namespace std ; | |||||
int main() { | |||||
cout << "1000 36\n"; | |||||
for(int i = 0 ; i < 1000 ; ++i) | |||||
{ | |||||
if(i % 36 == 1) | |||||
cout << "UNDO\n"; | |||||
else | |||||
cout << "NEW " << i << '\n'; | |||||
} | |||||
} |
@@ -0,0 +1,32 @@ | |||||
set noparent | |||||
root=. | |||||
# `build` rules | |||||
filter=-build/c++11 | |||||
filter=-build/header_guard | |||||
filter=-build/include | |||||
filter=-build/include_alpha | |||||
filter=-build/include_order | |||||
filter=-build/include_subdir | |||||
filter=-build/include_what_you_use | |||||
filter=-build/namespaces | |||||
# `legal` rules | |||||
filter=-legal/copyright | |||||
# `readability` rules | |||||
filter=-readability/braces | |||||
filter=-readability/casting | |||||
filter=-readability/namespace | |||||
filter=-readability/todo | |||||
# `runtime` rules | |||||
filter=-runtime/int | |||||
filter=-runtime/references | |||||
# `whitespace` rules | |||||
filter=-whitespace/blank_line | |||||
filter=-whitespace/braces | |||||
filter=-whitespace/comments | |||||
filter=-whitespace/end_of_line | |||||
filter=-whitespace/indent | |||||
filter=-whitespace/line_length | |||||
filter=-whitespace/newline | |||||
filter=-whitespace/operators | |||||
filter=-whitespace/parens | |||||
filter=-whitespace/tab |
@@ -0,0 +1,22 @@ | |||||
CXX = g++ | |||||
CXXFLAGS = -O0 -g -Wall -std=c++17 -DDEBUG | |||||
SRC = a.cpp b.cpp c.cpp | |||||
OBJ = ${SRC:.cpp=.o} | |||||
all: a b c | |||||
.o: ${OBJ} | |||||
${CXX} -c ${CXXFLAGS} $< | |||||
a: a.o | |||||
${CXX} -o $@ a.o ${LDFLAGS} | |||||
b: b.o | |||||
${CXX} -o $@ b.o ${LDFLAGS} | |||||
c: c.o | |||||
${CXX} -o $@ c.o ${LDFLAGS} | |||||
clean: | |||||
rm -f main ${OBJ} |
@@ -0,0 +1,273 @@ | |||||
#include <algorithm> | |||||
#include <chrono> | |||||
#include <deque> | |||||
#include <functional> | |||||
#include <iomanip> | |||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <vector> | |||||
#define MAXNUM 4000001 | |||||
class Date { | |||||
std::string date; | |||||
int year, month, day, total; | |||||
void dateToInt() { | |||||
year = stoi(date.substr(0, 4)); | |||||
month = stoi(date.substr(5, 2)); | |||||
day = stoi(date.substr(8, 2)); | |||||
total = year * 400 + month * 31 + day; | |||||
} | |||||
public: | |||||
Date() { | |||||
date = "1970-01-01"; | |||||
dateToInt(); | |||||
} | |||||
explicit Date(const std::string &d) { | |||||
date = d; | |||||
dateToInt(); | |||||
} | |||||
Date(const Date &d) { | |||||
date = d.date, year = d.year, month = d.month, day = d.day, | |||||
total = d.total; | |||||
} | |||||
Date(Date &&d) { | |||||
date = std::move(d.date); | |||||
year = d.year, month = d.month, day = d.day, total = d.total; | |||||
} | |||||
Date &operator=(Date d) { | |||||
date = d.date, year = d.year, month = d.month, day = d.day, | |||||
total = d.total; | |||||
return *this; | |||||
} | |||||
bool isLeap(int year) { | |||||
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) return true; | |||||
return false; | |||||
} | |||||
int maxDay(int month, int year) { | |||||
switch (month) { | |||||
case 4: | |||||
case 6: | |||||
case 9: | |||||
case 11: | |||||
return 30; | |||||
break; | |||||
case 2: | |||||
return (isLeap(year) ? 29 : 28); | |||||
break; | |||||
default: | |||||
return 31; | |||||
} | |||||
} | |||||
std::string getDate() { return date; } | |||||
int getTotal() { return total; } | |||||
void goNextDay() { | |||||
day++; | |||||
if (day > maxDay(month, year)) day = 1, month++; | |||||
if (month > 12) month = 1, year++; | |||||
total = year * 400 + month * 31 + day; | |||||
std::stringstream yearss, monthss, dayss; | |||||
yearss << std::setfill('0') << std::setw(4) << year; | |||||
monthss << std::setfill('0') << std::setw(2) << month; | |||||
dayss << std::setfill('0') << std::setw(2) << day; | |||||
date = yearss.str() + "-" + monthss.str() + "-" + dayss.str(); | |||||
} | |||||
// prefix ++ operator for getting the next day | |||||
Date &operator++() { | |||||
goNextDay(); | |||||
return *this; | |||||
} | |||||
Date operator++(int) { | |||||
Date res(*this); | |||||
goNextDay(); | |||||
return res; | |||||
} | |||||
operator int() const { return total; } | |||||
}; | |||||
class Transaction { | |||||
public: | |||||
Date date; | |||||
double money; | |||||
operator int() { return int(date); } | |||||
}; | |||||
// countingsort. Linear complexity. Works only for whole numbers, but can be | |||||
// modified to work with negative integers as well. It is perfect for the task, | |||||
// since it allows to sort the numbers and to not corrupt the initial order | |||||
template <typename T> | |||||
void countingsort(T arr[], size_t n) { | |||||
int c[MAXNUM]; | |||||
T temp[n + 1]; | |||||
std::fill(c, c + MAXNUM, 0); | |||||
for (size_t i = 0; i < n; ++i) c[(arr[i])]++; | |||||
for (size_t i = 1; i < MAXNUM; ++i) c[i] += c[i - 1]; | |||||
for (size_t i = n; i-- > 0;) { | |||||
temp[c[int(arr[i])]] = arr[i]; | |||||
c[int(arr[i])]--; | |||||
} | |||||
for (size_t i = 0; i < n; ++i) { | |||||
arr[i] = temp[i + 1]; | |||||
} | |||||
} | |||||
// merge sort. time complexity O(n*logn) in the worst case | |||||
template <typename T> | |||||
void mergesortlr(T arr[], size_t l, size_t r) { | |||||
if (r - l < 2 || r < l) return; | |||||
size_t m = (l + r) / 2; | |||||
mergesortlr<T>(arr, l, m); | |||||
mergesortlr<T>(arr, m, r); | |||||
size_t i = 0, j = 0, k = 0; | |||||
T temp[r - l]; | |||||
while (i < m - l && j < r - m) { | |||||
if (arr[l + i] < arr[m + j]) | |||||
temp[k++] = arr[l + i++]; | |||||
else | |||||
temp[k++] = arr[m + j++]; | |||||
} | |||||
while (i < m - l) temp[k++] = arr[l + i++]; | |||||
while (j < r - m) temp[k++] = arr[m + j++]; | |||||
for (size_t i = l; i < r; ++i) arr[i] = temp[i - l]; | |||||
} | |||||
template <typename T> | |||||
void mergesort(T arr[], size_t sz) { | |||||
mergesortlr<T>(arr, 0, sz); | |||||
} | |||||
// test a sorting function | |||||
template <typename T> | |||||
void testsort(std::function<void(T arr[], size_t sz)> test, size_t sz) { | |||||
srand(time(NULL)); | |||||
int a[sz], b[sz]; | |||||
for (size_t i = 0; i < sz; ++i) a[i] = b[i] = rand() % 30000; | |||||
using std::chrono::duration; | |||||
using std::chrono::duration_cast; | |||||
using std::chrono::high_resolution_clock; | |||||
using std::chrono::milliseconds; | |||||
// executing test sort | |||||
auto t1 = high_resolution_clock::now(); | |||||
test(a, sz); | |||||
auto t2 = high_resolution_clock::now(); | |||||
auto ms_int = duration_cast<milliseconds>(t2 - t1); | |||||
std::cout << "Test sort time: " << ms_int.count() << "ms\n"; | |||||
// executing std::sort | |||||
t1 = high_resolution_clock::now(); | |||||
std::sort(b, b + sz); | |||||
t2 = high_resolution_clock::now(); | |||||
ms_int = duration_cast<milliseconds>(t2 - t1); | |||||
std::cout << "std::sort time: " << ms_int.count() << "ms\n"; | |||||
// Checking correctness of the test sort | |||||
bool correct = 1; | |||||
for (size_t i = 0; i < sz; ++i) { | |||||
if (a[i] != b[i]) { | |||||
correct = 0; | |||||
break; | |||||
} | |||||
} | |||||
if (correct) | |||||
std::cout << "Test sort works properly...\n"; | |||||
else | |||||
std::cout << "Test sort failed...\n"; | |||||
} | |||||
int main() { | |||||
#ifdef DEBUG | |||||
std::cout << "Testing countingsort:\n"; | |||||
testsort<int>(&mergesort<int>, 10000); | |||||
std::cout << "\nTesting countingsort:\n"; | |||||
testsort<int>(&countingsort<int>, 10000); | |||||
Date feb("2020-02-01"), mar("2020-03-10"); | |||||
while (feb != mar) { | |||||
std::cout << feb.getDate() << '\n'; | |||||
feb++; | |||||
} | |||||
#endif | |||||
size_t n, d; | |||||
std::cin >> n >> d; | |||||
Transaction transactions[n]; | |||||
for (size_t i = 0; i < n; ++i) { | |||||
std::string datestr; | |||||
char c; | |||||
double money; | |||||
std::cin >> datestr >> c >> money; | |||||
transactions[i].date = Date(datestr); | |||||
transactions[i].money = money; | |||||
} | |||||
countingsort(transactions, n); | |||||
#ifdef DEBUG | |||||
for (size_t i = 0; i < n; ++i) | |||||
std::cout << transactions[i].date.getDate() << ' ' | |||||
<< transactions[i].money << '\n'; | |||||
#endif | |||||
int ans = 0; | |||||
// median | |||||
double mid = 0; | |||||
// using deque as a queue to iterate through it efficiently | |||||
std::deque<double> q; | |||||
Date today(transactions[0].date); | |||||
for (size_t i = 0; i < n; ++today) { | |||||
double sum = 0; | |||||
while (transactions[i].date.getTotal() <= today.getTotal()) { | |||||
sum += transactions[i++].money; | |||||
if (sum >= mid * 2.0 && q.size() == d) ans++; | |||||
if (i >= n) | |||||
break; | |||||
} | |||||
q.push_back(sum); | |||||
if (q.size() > d) q.pop_front(); | |||||
std::vector<double> v; | |||||
for (const auto &it : q) v.push_back(it); | |||||
if (v.size() == d) { | |||||
mergesort(&v[0], d); | |||||
if (d % 2 == 0) | |||||
mid = (v[(d - 1) / 2] + v[d / 2]) / 2.0; | |||||
else | |||||
mid = v[d / 2]; | |||||
} | |||||
} | |||||
std::cout << ans << '\n'; | |||||
return 0; | |||||
} |
@@ -0,0 +1,379 @@ | |||||
#include <algorithm> | |||||
#include <chrono> | |||||
#include <deque> | |||||
#include <functional> | |||||
#include <iomanip> | |||||
#include <iostream> | |||||
#include <list> | |||||
#include <map> | |||||
#include <sstream> | |||||
#include <vector> | |||||
class Date { | |||||
std::string date; | |||||
int year, month, day, total; | |||||
void dateToInt() { | |||||
year = stoi(date.substr(0, 4)); | |||||
month = stoi(date.substr(5, 2)); | |||||
day = stoi(date.substr(8, 2)); | |||||
total = year * 400 + month * 31 + day; | |||||
} | |||||
public: | |||||
Date() { | |||||
date = "1970-01-01"; | |||||
dateToInt(); | |||||
} | |||||
explicit Date(const std::string& d) { | |||||
date = d; | |||||
dateToInt(); | |||||
} | |||||
Date(const Date& d) { | |||||
date = d.date, year = d.year, month = d.month, day = d.day, | |||||
total = d.total; | |||||
} | |||||
Date(Date&& d) { | |||||
date = std::move(d.date); | |||||
year = d.year, month = d.month, day = d.day, total = d.total; | |||||
} | |||||
Date& operator=(Date d) { | |||||
date = d.date, year = d.year, month = d.month, day = d.day, | |||||
total = d.total; | |||||
return *this; | |||||
} | |||||
bool isLeap(int year) { | |||||
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) return true; | |||||
return false; | |||||
} | |||||
int maxDay(int month, int year) { | |||||
switch (month) { | |||||
case 4: | |||||
case 6: | |||||
case 9: | |||||
case 11: | |||||
return 30; | |||||
break; | |||||
case 2: | |||||
return (isLeap(year) ? 29 : 28); | |||||
break; | |||||
default: | |||||
return 31; | |||||
} | |||||
} | |||||
std::string getDate() const { return date; } | |||||
int getTotal() const { return total; } | |||||
void goNextDay() { | |||||
day++; | |||||
if (day > maxDay(month, year)) day = 1, month++; | |||||
if (month > 12) month = 1, year++; | |||||
total = year * 400 + month * 31 + day; | |||||
std::stringstream yearss, monthss, dayss; | |||||
yearss << std::setfill('0') << std::setw(4) << year; | |||||
monthss << std::setfill('0') << std::setw(2) << month; | |||||
dayss << std::setfill('0') << std::setw(2) << day; | |||||
date = yearss.str() + "-" + monthss.str() + "-" + dayss.str(); | |||||
} | |||||
// prefix ++ operator for getting the next day | |||||
Date& operator++() { | |||||
goNextDay(); | |||||
return *this; | |||||
} | |||||
Date operator++(int) { | |||||
Date res(*this); | |||||
goNextDay(); | |||||
return res; | |||||
} | |||||
operator int() const { return total; } | |||||
bool operator<(const Date& d) { return (total < d.total); } | |||||
bool operator>(const Date& d) { return (total > d.total); } | |||||
bool operator<=(const Date& d) { return (total <= d.total); } | |||||
bool operator>=(const Date& d) { return (total >= d.total); } | |||||
bool operator==(const Date& d) { return (total == d.total); } | |||||
friend std::ostream& operator<<(std::ostream& os, const Date& dt); | |||||
}; | |||||
std::ostream& operator<<(std::ostream& os, const Date& dt) { | |||||
os << dt.getDate(); | |||||
return os; | |||||
} | |||||
class Transaction { | |||||
public: | |||||
Date date; | |||||
double money; | |||||
operator int() { return int(date); } | |||||
}; | |||||
template <typename K, typename V> | |||||
class Btree; | |||||
template <typename K, typename V> | |||||
class TreeNode { | |||||
std::pair<K, V>* m_data; | |||||
int m_n, m_t; // current number of keys, and the maximum number of keys | |||||
TreeNode<K, V>** m_c; // children | |||||
bool m_leaf; // is true if the node is a leaf | |||||
TreeNode<K, V>(int t, bool leaf) : m_n(0), m_t(t), m_leaf(leaf) { | |||||
m_data = new std::pair<K, V>[2 * t]; | |||||
m_c = new TreeNode<K, V>*[2 * t]; | |||||
} | |||||
~TreeNode<K, V>() { | |||||
delete[] m_data; | |||||
if (!m_leaf && m_n > 0) | |||||
for (int i = 0; i <= m_n; ++i) delete m_c[i]; | |||||
delete[] m_c; | |||||
} | |||||
// Insert a new key in the subtree. Assumption: node must be non-full | |||||
void insert(K key, V value) { | |||||
int i = m_n - 1; // last child | |||||
if (m_leaf) { | |||||
// move all greater keys one position right and find the location of | |||||
// a new key | |||||
while (i >= 0 && m_data[i].first > key) { | |||||
m_data[i + 1] = m_data[i]; | |||||
i--; | |||||
} | |||||
m_data[i + 1] = {key, value}; | |||||
m_n++; | |||||
} else { | |||||
// Find the child which is going to have the new key | |||||
while (i >= 0 && m_data[i].first > key) i--; | |||||
// if the child is full | |||||
if (m_c[i + 1]->m_n == 2 * m_t - 1) { | |||||
splitChild(i + 1, m_c[i + 1]); | |||||
if (m_data[i + 1].first < key) i++; | |||||
} | |||||
m_c[i + 1]->insert(key, value); | |||||
} | |||||
} | |||||
// split the child 'child' of this node. Assumption: child must be full | |||||
void splitChild(int i, TreeNode<K, V>* child) { | |||||
TreeNode<K, V>* temp = new TreeNode<K, V>(child->m_t, child->m_leaf); | |||||
temp->m_n = m_t - 1; | |||||
for (int j = 0; j < m_t - 1; j++) | |||||
temp->m_data[j] = child->m_data[j + m_t]; | |||||
if (!child->m_leaf) { | |||||
for (int j = 0; j < m_t; j++) temp->m_c[j] = child->m_c[j + m_t]; | |||||
} | |||||
child->m_n = m_t - 1; | |||||
for (int j = m_n; j >= i + 1; --j) m_c[j + 1] = m_c[j]; | |||||
m_c[i + 1] = temp; | |||||
for (int j = m_n - 1; j >= i; --j) m_data[j + 1] = m_data[j]; | |||||
m_data[i] = child->m_data[m_t - 1]; | |||||
m_n++; | |||||
} | |||||
void traverse() { | |||||
for (int i = 0; i < m_n; i++) { | |||||
if (!m_leaf) m_c[i]->traverse(); | |||||
std::cout << m_data[i].first << ' ' << m_data[i].second << ' '; | |||||
} | |||||
if (!m_leaf) m_c[m_n]->traverse(); | |||||
std::cout << '\n'; | |||||
} | |||||
// recursive search O(logn) | |||||
const TreeNode<K, V>* search(K key) const { | |||||
int i = 0; | |||||
while (i < m_n && m_data[i].first < key) i++; | |||||
if (m_data[i].first == key) return this; | |||||
if (m_leaf == true) return NULL; | |||||
return m_c[i]->search(key); | |||||
} | |||||
// range query | |||||
std::list<V> search(const K& from, const K& to) const { | |||||
std::list<V> res; | |||||
if (m_leaf) { | |||||
for (int i = 0; i < m_n; ++i) { | |||||
if (m_data[i].first >= from && m_data[i].first <= to) | |||||
res.push_back(m_data[i].second); | |||||
} | |||||
} else { | |||||
if (m_data[0].first >= from) { | |||||
res.splice(res.end(), m_c[0]->search(from, to)); | |||||
if (m_data[0].first >= from && m_data[0].first <= to) | |||||
res.push_back(m_data[0].second); | |||||
} | |||||
K prev = m_data[0].first; | |||||
for (int i = 1; i < m_n; ++i) { | |||||
if (prev > to) break; | |||||
if (m_data[i].first >= from) { | |||||
res.splice(res.end(), m_c[i]->search(from, to)); | |||||
} | |||||
if (m_data[i].first >= from && m_data[i].first <= to) | |||||
res.push_back(m_data[i].second); | |||||
prev = m_data[i].first; | |||||
} | |||||
if (prev <= to) { | |||||
res.splice(res.end(), m_c[m_n]->search(from, to)); | |||||
} | |||||
} | |||||
return res; | |||||
} | |||||
friend class Btree<K, V>; | |||||
}; | |||||
template <typename K, typename V> | |||||
class IRangeMap { | |||||
virtual int size() const = 0; | |||||
virtual bool isEmpty() const = 0; | |||||
virtual void add(const K& key, const V& value) = 0; | |||||
virtual bool contains(const K& key) const = 0; | |||||
virtual V& lookup(const K& key) const = 0; | |||||
virtual std::list<V> lookupRange(const K& from, const K& to) const = 0; | |||||
}; | |||||
template <typename K, typename V> | |||||
class Btree : IRangeMap<K, V> { | |||||
TreeNode<K, V>* m_root; | |||||
int m_sz, m_t; | |||||
public: | |||||
explicit Btree(int t) : m_root(nullptr), m_sz(0), m_t(t) {} | |||||
~Btree<K, V>() { delete m_root; } | |||||
// search a key in the tree. Returns a pointer to a TreeNode which has the | |||||
// key. | |||||
const TreeNode<K, V>* search(const K& key) const { | |||||
return (m_root == NULL) ? NULL : m_root->search(key); | |||||
} | |||||
// Return the value of the key. Assumption: key exists in the tree | |||||
V& lookup(const K& key) const { | |||||
const auto it = search(key); | |||||
if (it == NULL) throw "key doesn't exist!"; | |||||
for (int i = 0; i < m_t * 2 - 1; ++i) | |||||
if (it->m_data[i].first == key) return it->m_data[i].second; | |||||
throw "key doesn't exist!"; | |||||
} | |||||
bool contains(const K& key) const { return (search(key) != NULL); } | |||||
std::list<V> lookupRange(const K& from, const K& to) const { | |||||
if (m_root == NULL) return std::list<V>(); | |||||
return m_root->search(from, to); | |||||
} | |||||
void traverse() { | |||||
if (m_root) m_root->traverse(); | |||||
} | |||||
void add(const K& key, const V& value) { | |||||
if (key == Date("2021-11-11")) { | |||||
Date d = Date("2021-11-11"); | |||||
} | |||||
if (m_root == NULL) { | |||||
m_root = new TreeNode<K, V>(m_t, true); | |||||
m_root->m_data[0] = {key, value}; | |||||
m_root->m_n = 1; | |||||
} else { | |||||
// if root is full | |||||
if (m_root->m_n == m_t * 2 - 1) { | |||||
TreeNode<K, V>* temp = new TreeNode<K, V>(m_t, false); | |||||
// rearrange root and its child | |||||
temp->m_c[0] = m_root; | |||||
// split the old root | |||||
temp->splitChild(0, m_root); | |||||
int i = 0; | |||||
if (temp->m_data[0].first < key) i++; | |||||
temp->m_c[i]->insert(key, value); | |||||
m_root = temp; | |||||
} else | |||||
m_root->insert(key, value); | |||||
} | |||||
m_sz++; | |||||
} | |||||
int size() const { return m_sz; } | |||||
bool isEmpty() const { return (m_sz == 0); } | |||||
}; | |||||
int main() { | |||||
#ifdef DEBUG | |||||
freopen("test", "r", stdin); | |||||
#endif | |||||
int n; | |||||
std::cin >> n; | |||||
Btree<Date, double> map(2); | |||||
//std::map<Date, double> mp; | |||||
for (int i = 0; i < n; ++i) { | |||||
std::string datestr, type; | |||||
double money; | |||||
std::cin >> datestr; | |||||
if (datestr == "REPORT") { | |||||
std::string from, to; | |||||
std::cin >> type >> from >> type >> to; | |||||
std::list<double> l = map.lookupRange(Date(from), Date(to)); | |||||
double ans = 0, ans2 = 0; | |||||
for (const auto& it : l) ans += it; | |||||
/* | |||||
auto itfrom = mp.lower_bound(Date(from)), | |||||
itto = mp.upper_bound(Date(to)); | |||||
for (auto it = itfrom; it != itto; ++it) { | |||||
ans2 += it->second; | |||||
std::cout << it->first << ' ' << it->second << '\n'; | |||||
} | |||||
*/ | |||||
std::cout << ans << '\n'; | |||||
} else { | |||||
std::cin >> type >> money; | |||||
if (type == "WITHDRAW") money *= -1; | |||||
Date d(datestr); | |||||
//mp[d] += money; | |||||
if (map.contains(d)) { | |||||
map.lookup(d) += money; | |||||
} else { | |||||
map.add(Date(datestr), money); | |||||
} | |||||
} | |||||
} | |||||
#ifdef DEBUG | |||||
#endif | |||||
} | |||||
@@ -0,0 +1,163 @@ | |||||
#include <algorithm> | |||||
#include <chrono> | |||||
#include <deque> | |||||
#include <functional> | |||||
#include <iomanip> | |||||
#include <iostream> | |||||
#include <list> | |||||
#include <map> | |||||
#include <sstream> | |||||
#include <unordered_map> | |||||
#include <vector> | |||||
#define MaxN 2147483647 | |||||
#define MinN -1 | |||||
template <typename K, typename V> | |||||
class Obj { | |||||
public: | |||||
K k; | |||||
V v; | |||||
Obj() {} | |||||
Obj(K key, V value) : k(key), v(value) {} | |||||
bool operator<(const Obj &o) const { | |||||
if (k == o.k) return (v < o.v); | |||||
return (k < o.k); | |||||
} | |||||
bool operator>(const Obj &o) const { | |||||
if (k == o.k) return (v > o.v); | |||||
return (k > o.k); | |||||
} | |||||
Obj<K, V> operator=(const Obj<K, V> &o) { | |||||
k = o.k; | |||||
v = o.v; | |||||
return *this; | |||||
} | |||||
bool operator==(const Obj<K, V> &o) { | |||||
if (k == o.k && v == o.v) | |||||
return true; | |||||
return false; | |||||
} | |||||
}; | |||||
template <typename K, typename V> | |||||
class IPriorityQueue { | |||||
virtual void insert(const Obj<K, V> &item) = 0; | |||||
virtual Obj<K, V> findMin() = 0; | |||||
virtual Obj<K, V> extractMin() = 0; | |||||
virtual void decreaseKey(Obj<K, V> &item, K newKey) = 0; | |||||
virtual void remove(Obj<K, V> &item) = 0; | |||||
virtual void unite(Obj<K, V> &anotherQueue) = 0; | |||||
}; | |||||
template <typename K, typename V> | |||||
class PriorityQueue : IPriorityQueue<K, V> { | |||||
Obj<K, V> *m_data; | |||||
int sz, mxsz; | |||||
std::unordered_map<V, int> map; | |||||
public: | |||||
PriorityQueue<K, V>(int capacity) : sz(0), mxsz(capacity) { | |||||
m_data = new Obj<K, V>[capacity](); | |||||
} | |||||
// get indexes | |||||
int parent(int i) { return (i - 1) / 2; } | |||||
int left(int i) { return (2 * i + 1); } | |||||
int right(int i) { return (2 * i + 2); } | |||||
int findId(const Obj<K, V> &item) { | |||||
// I used unordered_map to find the index of the item by value | |||||
return map[item.v]; | |||||
} | |||||
Obj<K, V> findMin() { return m_data[0]; } | |||||
// insert an object. O(logn) | |||||
void insert(const Obj<K, V> &item) { | |||||
if (sz == mxsz) { | |||||
throw "Couldn't insert!"; | |||||
} | |||||
sz++; | |||||
int i = sz - 1, j = sz - 1; | |||||
m_data[i] = item; | |||||
while (i != 0 && m_data[parent(i)] > m_data[i]) { | |||||
swap(m_data[i], m_data[parent(i)]); | |||||
j = i; | |||||
i = parent(i); | |||||
if (i == 0) | |||||
break; | |||||
} | |||||
map[item.v] = j; | |||||
} | |||||
// decrease the key of an object. O(logn) | |||||
void decreaseKey(Obj<K, V> &item, K newKey) { | |||||
int i = findId(item); | |||||
m_data[i].k = newKey; | |||||
while (i != 0 && m_data[parent(i)] > m_data[i]) { | |||||
swap(m_data[i], m_data[parent(i)]); | |||||
i = parent(i); | |||||
} | |||||
} | |||||
// return minimum and pop it from the queue. O(logn) | |||||
Obj<K, V> extractMin() { | |||||
if (sz <= 0) return Obj<K, V>(MinN, std::string()); | |||||
if (sz == 1) { | |||||
sz--; | |||||
return m_data[0]; | |||||
} | |||||
Obj<K, V> root = m_data[0]; | |||||
m_data[0] = m_data[sz - 1]; | |||||
sz--; | |||||
MinHeapify(0); | |||||
return root; | |||||
} | |||||
// delete the object from the queue. O(logn) | |||||
void remove(Obj<K, V> &item) { | |||||
decreaseKey(item, K()); | |||||
extractMin(); | |||||
} | |||||
// stabilize the heap recursively. O(logn) | |||||
void MinHeapify(int i) { | |||||
int l = left(i); | |||||
int r = right(i); | |||||
int mn = i; | |||||
if (l < sz && m_data[l] < m_data[i]) mn = l; | |||||
if (r < sz && m_data[r] < m_data[mn]) mn = r; | |||||
if (mn != i) { | |||||
swap(m_data[i], m_data[mn]); | |||||
MinHeapify(mn); | |||||
} | |||||
} | |||||
void unite(Obj<K, V> &anotherQueue) {} | |||||
}; | |||||
int main() { | |||||
int n; | |||||
std::cin >> n; | |||||
PriorityQueue<int, std::string> q(1000000); | |||||
while (n--) { | |||||
std::string query, branch; | |||||
std::cin >> query; | |||||
if (query == "ADD") { | |||||
int value; | |||||
std::cin >> branch >> value; | |||||
q.insert(Obj<int, std::string>(value, branch)); | |||||
} else { | |||||
std::cout << q.extractMin().v << '\n'; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
24 | |||||
2021-10-18 DEPOSIT 42 | |||||
2021-10-09 WITHDRAW 97 | |||||
2021-11-01 DEPOSIT 10 | |||||
2021-09-07 WITHDRAW 43 | |||||
2021-12-09 DEPOSIT 45 | |||||
2021-10-08 DEPOSIT 5 | |||||
2021-09-22 WITHDRAW 54 | |||||
2021-11-25 DEPOSIT 47 | |||||
2021-11-02 DEPOSIT 80 | |||||
2021-12-05 DEPOSIT 27 | |||||
2021-09-22 WITHDRAW 46 | |||||
2021-09-21 DEPOSIT 76 | |||||
2021-11-15 DEPOSIT 79 | |||||
2021-09-12 DEPOSIT 65 | |||||
2021-09-12 DEPOSIT 15 | |||||
2021-10-16 WITHDRAW 52 | |||||
2021-09-10 DEPOSIT 3 | |||||
2021-10-12 DEPOSIT 58 | |||||
2021-11-01 WITHDRAW 88 | |||||
2021-10-02 WITHDRAW 14 | |||||
2021-10-03 DEPOSIT 46 | |||||
2021-12-08 WITHDRAW 56 | |||||
2021-11-11 WITHDRAW 97 | |||||
REPORT FROM 2021-09-24 TO 2021-12-12 |
@@ -0,0 +1,205 @@ | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <ctype.h> | |||||
#ifdef DEBUG | |||||
# define D(x) x | |||||
#else | |||||
# define D(x) | |||||
#endif | |||||
struct item { | |||||
char name[40] ; | |||||
float size ; | |||||
int amount; | |||||
char mu[10] ; | |||||
} ; | |||||
struct rentt { | |||||
char name[40] ; | |||||
int day, month, year, hours, minutes, seconds ; | |||||
struct item items[256] ; | |||||
} ; | |||||
int main(int argc, char *argv[]) | |||||
{ | |||||
FILE * inpf = fopen("input.txt", "r"), | |||||
* outf = fopen("output.txt", "w") ; | |||||
// output buffer | |||||
char buf[100000] = "\0" ; | |||||
// the actual rent | |||||
struct rentt rent[500] ; | |||||
// input | |||||
int cur = 0 ; | |||||
while(fgets(rent[cur].name, 32, inpf) != NULL) { | |||||
// get rid of \n at the end | |||||
int sz = strlen(rent[cur].name) ; | |||||
if(rent[cur].name[sz-1] == '\n') | |||||
rent[cur].name[--sz] = '\0' ; | |||||
// validate name | |||||
if(sz < 2 || sz > 30) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
for(int i = 0 ; i < sz ; ++i) | |||||
if(!isalpha(rent[cur].name[i]) && rent[cur].name[i] != ' ') | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
// enter date and validate input | |||||
char date[100] ; | |||||
fgets(date, 100, inpf) ; | |||||
if(!(isdigit(date[0]) , isdigit(date[1]) , date[2] == '/' | |||||
&& isdigit(date[3]) && isdigit(date[4]) && date[5] == '/' | |||||
&& isdigit(date[6]) && isdigit(date[7]) | |||||
&& isdigit(date[8]) && isdigit(date[9]) && date[10] == ' ' | |||||
&& isdigit(date[11]) && isdigit(date[12]) && date[13] == ':' | |||||
&& isdigit(date[14]) && isdigit(date[15]) && date[16] == ':' | |||||
&& isdigit(date[17]) && isdigit(date[18]))) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
sscanf(date, "%d/%d/%d %d:%d:%d", &rent[cur].day, &rent[cur].month, &rent[cur].year, &rent[cur].hours, &rent[cur].minutes, &rent[cur].seconds) ; | |||||
// validate date | |||||
if(rent[cur].month == 1 || rent[cur].month == 3 || rent[cur].month == 5 | |||||
|| rent[cur].month == 7 || rent[cur].month == 8 | |||||
|| rent[cur].month == 10 || rent[cur].month == 12) | |||||
{ | |||||
if(rent[cur].day > 31) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
} else if( rent[cur].month == 2) { | |||||
// leap year case | |||||
if(rent[cur].year % 400 == 0) { | |||||
if(rent[cur].day > 29) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
} else if(rent[cur].year % 4 == 0 && rent[cur].year % 100 != 0) { | |||||
if( rent[cur].day > 29) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
} else { | |||||
if(rent[cur].day > 28) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
} | |||||
} else if ( rent[cur].month >= 1 && rent[cur].month <= 12) { | |||||
if(rent[cur].day > 30) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
} else | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
// validate time | |||||
if(!(rent[cur].hours >= 0 && rent[cur].hours <= 23 | |||||
&& rent[cur].minutes >= 0 && rent[cur].minutes <= 59 | |||||
&& rent[cur].seconds >= 0 && rent[cur].seconds <= 59)) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
sprintf(buf + strlen(buf), "%s has rented ", rent[cur].name) ; | |||||
int curi = 0 ; | |||||
while(1) { | |||||
char temp[256] ; | |||||
char lol = fgets(temp, 256, inpf) ; | |||||
// check if it is the last line | |||||
if(lol == NULL || temp[0] == '\n') break ; | |||||
// get rid of \n at the end | |||||
sz = strlen(temp) ; | |||||
if(temp[sz-1] == '\n') | |||||
temp[--sz] = '\0' ; | |||||
if(temp[sz] != '\0') | |||||
temp[++sz] = '\0' ; | |||||
// enter and validate the name of an item | |||||
int curp = 0 ; | |||||
for(int i = 0 ; i < sz ; ++i) { | |||||
if(isalpha(temp[i]) || temp[i] == ' ') { | |||||
rent[cur].items[curi].name[curp++] = temp[i] ; | |||||
} | |||||
else { | |||||
if(curp == 0) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
if(rent[cur].items[curi].name[curp-1] == ' ') | |||||
rent[cur].items[curi].name[--curp] = '\0' ; | |||||
else | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
break ; | |||||
} | |||||
} | |||||
// copy only the size, the amount and the measurement unit of an item | |||||
char vals[256] ; | |||||
memcpy(vals, temp+curp, strlen(temp+curp)+1) ; | |||||
// format them | |||||
sscanf(vals, "%f%d%s", &rent[cur].items[curi].size, | |||||
&rent[cur].items[curi].amount, | |||||
rent[cur].items[curi].mu) ; | |||||
D(printf("vals: %s\nsz: %f\nam: %d\nmu: %s\n", | |||||
temp, rent[cur].items[curi].size, | |||||
rent[cur].items[curi].amount, | |||||
rent[cur].items[curi].mu)) ; | |||||
// validation | |||||
if(!(rent[cur].items[curi].size > 0.0 && rent[cur].items[curi].size <= 200.0 | |||||
&& rent[cur].items[curi].amount > 0 && rent[cur].items[curi].amount <= 30 | |||||
&& (strcmp(rent[cur].items[curi].mu, "pair") == 0 | |||||
|| strcmp(rent[cur].items[curi].mu, "pcs") == 0))) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
// the case when there are several pairs | |||||
if(strcmp(rent[cur].items[curi].mu, "pair") == 0 | |||||
&& rent[cur].items[curi].amount > 1) | |||||
sprintf(rent[cur].items[curi].mu, "pairs") ; | |||||
curi ++ ; | |||||
} | |||||
// append items to the buffer | |||||
if(curi == 1) { | |||||
sprintf(buf + strlen(buf), "%d %s of %s of size %g", | |||||
rent[cur].items[0].amount, rent[cur].items[0].mu, | |||||
rent[cur].items[0].name, rent[cur].items[0].size) ; | |||||
} else for(int i = 0 ; i < curi ; ++i) | |||||
{ | |||||
if(i == curi-1) | |||||
sprintf(buf + strlen(buf), " and %d %s of %s of size %g", | |||||
rent[cur].items[i].amount, rent[cur].items[i].mu, | |||||
rent[cur].items[i].name, rent[cur].items[i].size) ; | |||||
else if(i == 0) | |||||
sprintf(buf + strlen(buf), "%d %s of %s of size %g", | |||||
rent[cur].items[i].amount, rent[cur].items[i].mu, | |||||
rent[cur].items[i].name, rent[cur].items[i].size) ; | |||||
else | |||||
sprintf(buf + strlen(buf), ", %d %s of %s of size %g", | |||||
rent[cur].items[i].amount, rent[cur].items[i].mu, | |||||
rent[cur].items[i].name, rent[cur].items[i].size) ; | |||||
} | |||||
// if there is no any item | |||||
if(curi <= 0) | |||||
return fprintf(outf, "Invalid input!"), 0 ; | |||||
// append the date/time to the buffer | |||||
sprintf(buf + strlen(buf), " on %d%d/%d%d/%d%d%d%d at %d%d:%d%d:%d%d.\n", | |||||
rent[cur].day/10, rent[cur].day%10, | |||||
rent[cur].month/10, rent[cur].month%10, | |||||
rent[cur].year/1000, rent[cur].year/100%10, | |||||
rent[cur].year/10%10, rent[cur].year%10, | |||||
rent[cur].hours/10, rent[cur].hours%10, | |||||
rent[cur].minutes/10, rent[cur].minutes%10, | |||||
rent[cur].seconds/10, rent[cur].seconds%10) ; | |||||
cur++ ; | |||||
} | |||||
// print out the buffer | |||||
fprintf(outf, "%s", buf) ; | |||||
} |
@@ -0,0 +1,51 @@ | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <string> | |||||
#include <unordered_set> | |||||
#include <vector> | |||||
bool isConcat(std::string &s, int pos, std::vector<std::string> &v, | |||||
std::unordered_set<int> st) { | |||||
if (st.size() == v.size()) return 1; | |||||
for (int i = 0; i < v.size(); ++i) { | |||||
bool ok = 1; | |||||
if (st.find(i) != st.end()) continue; | |||||
if (v[i].size() > s.size() - pos) continue; | |||||
for (int j = 0; j < v[i].size(); ++j) { | |||||
if (s[pos + j] != v[i][j]) { | |||||
ok = 0; | |||||
break; | |||||
} | |||||
} | |||||
if (ok) { | |||||
st.insert(i); | |||||
if (isConcat(s, pos + v[i].size(), v, st)) return 1; | |||||
st.erase(i); | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
int main() { | |||||
std::ifstream in; | |||||
std::ofstream out; | |||||
in.open("input.txt"); | |||||
out.open("output.txt"); | |||||
std::string s, temp; | |||||
in >> s; | |||||
std::vector<std::string> v; | |||||
while (in >> temp) { | |||||
v.push_back(temp); | |||||
} | |||||
for (int i = 0; i < s.size(); ++i) { | |||||
std::unordered_set<int> st; | |||||
if (isConcat(s, i, v, st)) out << i << ' '; | |||||
} | |||||
} |
@@ -0,0 +1,161 @@ | |||||
#include <fstream> | |||||
#include <iostream> | |||||
template <class T> | |||||
class Node { | |||||
public: | |||||
Node<T>(T item) { | |||||
value = item; | |||||
next = NULL; | |||||
} | |||||
T value; | |||||
Node<T>* next; | |||||
}; | |||||
template <class T> | |||||
class List { | |||||
Node<T>* head; | |||||
int sz; | |||||
public: | |||||
List<T>() { | |||||
head = NULL; | |||||
sz = 0; | |||||
} | |||||
// Create a list from nodes. O(n) | |||||
List<T>(Node<T>* node) { | |||||
head = node; | |||||
sz = 1; | |||||
while (node->next != NULL) sz++; | |||||
} | |||||
int size() const { return sz; } | |||||
Node<T>* begin() const { return head; } | |||||
// Return the n'th Node address O(n) | |||||
Node<T>* seek(int pos) const { | |||||
Node<T>* cur = head; | |||||
for (int i = 0; i < pos; ++i) { | |||||
cur = cur->next; | |||||
} | |||||
return cur; | |||||
} | |||||
// Remove the next node O(1) | |||||
void remove(Node<T>* node) { | |||||
Node<T>* nextNode = node->next; | |||||
node->next = nextNode->next; | |||||
delete nextNode; | |||||
sz--; | |||||
} | |||||
// remove the n'th node O(n) | |||||
void remove(int nodeNumber) { | |||||
if (sz == 0) std::abort(); | |||||
Node<T>* cur = head; | |||||
if (nodeNumber == 0) { | |||||
head = head->next; | |||||
delete cur; | |||||
sz--; | |||||
return; | |||||
} | |||||
for (int i = 0; i < nodeNumber - 1; ++i) { | |||||
cur = cur->next; | |||||
} | |||||
remove(cur); | |||||
} | |||||
// insert a Node. O(n) | |||||
void insert(Node<T>* node, int pos) { | |||||
Node<T>* cur = head; | |||||
if (pos > sz) std::abort(); | |||||
if (pos == 0) { | |||||
node->next = head; | |||||
head = node; | |||||
sz++; | |||||
return; | |||||
} | |||||
for (int i = 0; i < pos - 1; ++i) { | |||||
cur = cur->next; | |||||
} | |||||
node->next = cur->next; | |||||
cur->next = node; | |||||
sz++; | |||||
} | |||||
// insert a Node. O(n) | |||||
void insert(T item, int pos) { | |||||
Node<T>* node = new Node<T>(item); | |||||
insert(node, pos); | |||||
} | |||||
// insert a Node. O(n) | |||||
void push_back(Node<T>* node) { insert(node, sz); } | |||||
// insert an item. O(n) | |||||
void push_back(T item) { insert(item, sz); } | |||||
// Swap every two adjacent Nodes | |||||
void swapAdjacent() { | |||||
Node<T>*cur = head, *curNext = head->next, *curPrev = NULL; | |||||
for (int i = 0; i < (sz % 2 ? sz - 1 : sz); i += 2) { | |||||
if (curPrev == NULL) | |||||
head = curNext; | |||||
else | |||||
curPrev->next = curNext; | |||||
cur->next = curNext->next; | |||||
curNext->next = cur; | |||||
curPrev = cur; | |||||
if (cur->next) { | |||||
cur = cur->next; | |||||
curNext = cur->next; | |||||
} | |||||
} | |||||
} | |||||
// convert the list to string. O(n) | |||||
std::string toString() { | |||||
std::string ans = ""; | |||||
Node<T>* cur = head; | |||||
while (cur) { | |||||
ans += std::to_string(cur->value) + " "; | |||||
cur = cur->next; | |||||
} | |||||
return ans; | |||||
} | |||||
}; | |||||
int main() { | |||||
std::ifstream in; | |||||
in.open("input.txt"); | |||||
std::ofstream out; | |||||
out.open("output.txt"); | |||||
List<int> l; | |||||
int a; | |||||
while (in >> a) { | |||||
l.push_back(a); | |||||
} | |||||
l.swapAdjacent(); | |||||
out << l.toString() << '\n'; | |||||
} |
@@ -0,0 +1,78 @@ | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <list> | |||||
#include <memory> | |||||
#include <vector> | |||||
// find determinant of a square matrix starting from the row 'row' | |||||
double det(std::list<std::shared_ptr<std::vector<double>>> &m, int row) { | |||||
if (m.size() == 2) { | |||||
double a, b, c, d; | |||||
auto it = m.begin(); | |||||
a = (**it)[row], c = (**it)[row+1]; | |||||
it++; | |||||
b = (**it)[row], d = (**it)[row+1]; | |||||
return (a * d) - (b * c); | |||||
} | |||||
double res = 0; | |||||
auto it = m.begin(); | |||||
for (size_t i = 0; i < m.size(); ++i) { | |||||
// the even rows (else) and odd rows (if) | |||||
if (i & 1) { | |||||
std::shared_ptr<std::vector<double>> v = *it; | |||||
auto temp = it; | |||||
temp++; | |||||
m.erase(it); | |||||
res -= (*v)[row] * det(m, row + 1); | |||||
m.insert(temp, v); | |||||
} else { | |||||
std::shared_ptr<std::vector<double>> v = *it; | |||||
auto temp = it; | |||||
temp++; | |||||
m.erase(it); | |||||
res += (*v)[row] * det(m, row + 1); | |||||
m.insert(temp, v); | |||||
} | |||||
it++; | |||||
} | |||||
return res; | |||||
} | |||||
int main() { | |||||
std::ifstream in; | |||||
std::ofstream out; | |||||
in.open("input.txt"); | |||||
out.open("output.txt"); | |||||
char c; | |||||
std::vector<std::vector<double>> v; | |||||
for (size_t i = 0; in >> c; ++i) { | |||||
if (c == '{' || c == ',') { | |||||
v.push_back(std::vector<double>()); | |||||
for (size_t j = 0; in >> c; ++j) { | |||||
if (c == '{' || c == ',') { | |||||
int a; | |||||
in >> a; | |||||
v[i].push_back(a); | |||||
} else { | |||||
break; | |||||
} | |||||
} | |||||
} else { | |||||
break; | |||||
} | |||||
} | |||||
std::list<std::shared_ptr<std::vector<double>>> m; | |||||
for (size_t i = 0; i < v.size(); ++i) { | |||||
m.push_back( | |||||
std::make_shared<std::vector<double>>(std::vector<double>())); | |||||
auto it = m.end(); | |||||
it--; | |||||
for (size_t j = 0; j < v.size(); ++j) { | |||||
(*it)->push_back(v[j][i]); | |||||
} | |||||
} | |||||
out << det(m, 0) << '\n'; | |||||
} |
@@ -0,0 +1,105 @@ | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <list> | |||||
#include <memory> | |||||
#include <vector> | |||||
// find determinant of a square matrix starting from the row 'row' | |||||
double det(std::list<std::shared_ptr<std::vector<double>>> &m, int row) { | |||||
if (m.size() == 2) { | |||||
double a, b, c, d; | |||||
auto it = m.begin(); | |||||
a = (**it)[row], c = (**it)[row + 1]; | |||||
it++; | |||||
b = (**it)[row], d = (**it)[row + 1]; | |||||
return (a * d) - (b * c); | |||||
} | |||||
double res = 0; | |||||
auto it = m.begin(); | |||||
for (size_t i = 0; i < m.size(); ++i) { | |||||
// the even rows (else) and odd rows (if) | |||||
if (i & 1) { | |||||
std::shared_ptr<std::vector<double>> v = *it; | |||||
auto temp = it; | |||||
temp++; | |||||
m.erase(it); | |||||
res -= (*v)[row] * det(m, row + 1); | |||||
m.insert(temp, v); | |||||
} else { | |||||
std::shared_ptr<std::vector<double>> v = *it; | |||||
auto temp = it; | |||||
temp++; | |||||
m.erase(it); | |||||
res += (*v)[row] * det(m, row + 1); | |||||
m.insert(temp, v); | |||||
} | |||||
it++; | |||||
} | |||||
return res; | |||||
} | |||||
int main() { | |||||
std::ifstream in; | |||||
std::ofstream out; | |||||
in.open("input.txt"); | |||||
out.open("output.txt"); | |||||
char c; | |||||
std::vector<std::vector<double>> v; | |||||
for (size_t i = 0; in >> c; ++i) { | |||||
if (c == '{' || c == ',') { | |||||
v.push_back(std::vector<double>()); | |||||
for (size_t j = 0; in >> c; ++j) { | |||||
if (c == '{' || c == ',') { | |||||
int a; | |||||
in >> a; | |||||
v[i].push_back(a); | |||||
} else { | |||||
break; | |||||
} | |||||
} | |||||
} else { | |||||
break; | |||||
} | |||||
} | |||||
std::list<std::shared_ptr<std::vector<double>>> m; | |||||
for (size_t i = 0; i < v.size(); ++i) { | |||||
m.push_back( | |||||
std::make_shared<std::vector<double>>(std::vector<double>())); | |||||
auto it = m.end(); | |||||
it--; | |||||
for (size_t j = 0; j < v.size(); ++j) { | |||||
(*it)->push_back(v[j][i]); | |||||
} | |||||
} | |||||
double dt = det(m, 0); | |||||
std::vector<std::vector<double>> a(3); | |||||
a[0].push_back(v[1][1] * v[2][2] - v[1][2] * v[2][1]); | |||||
a[0].push_back(v[0][1] * v[2][2] - v[2][1] * v[0][2]); | |||||
a[0].push_back(v[0][1] * v[1][2] - v[1][1] * v[0][2]); | |||||
a[1].push_back(v[1][0] * v[2][2] - v[2][0] * v[1][2]); | |||||
a[1].push_back(v[0][0] * v[2][2] - v[2][0] * v[0][2]); | |||||
a[1].push_back(v[0][0] * v[1][2] - v[1][0] * v[0][2]); | |||||
a[2].push_back(v[1][0] * v[2][1] - v[2][0] * v[1][1]); | |||||
a[2].push_back(v[0][0] * v[2][1] - v[2][0] * v[0][1]); | |||||
a[2].push_back(v[0][0] * v[1][1] - v[1][0] * v[0][1]); | |||||
a[0][1] *= -1; | |||||
a[1][0] *= -1; | |||||
a[1][2] *= -1; | |||||
a[2][1] *= -1; | |||||
out.precision(2); | |||||
for (auto i : a) { | |||||
for (auto j : i) { | |||||
j /= dt; | |||||
out << std::fixed << j << ' '; | |||||
} | |||||
out << '\n'; | |||||
} | |||||
} |
@@ -0,0 +1,166 @@ | |||||
#include <fstream> | |||||
#include <iostream> | |||||
#include <stdexcept> | |||||
#include <vector> | |||||
class Matrix { | |||||
std::vector<std::vector<double>> m_data; | |||||
public: | |||||
Matrix() {} | |||||
// Copy constructor combined with transpose | |||||
Matrix(const Matrix& m, bool transpose = 0) { | |||||
const std::vector<std::vector<double>>& data = m.GetData(); | |||||
if (transpose) { | |||||
if (data.size()) { | |||||
int rows = data[0].size(), cols = data.size(); | |||||
m_data.resize(rows); | |||||
for (auto& i : m_data) i.resize(cols, 0); | |||||
for (int i = 0; i < rows; ++i) | |||||
for (int j = 0; j < cols; ++j) m_data[i][j] = data[j][i]; | |||||
} | |||||
} else { | |||||
m_data = data; | |||||
} | |||||
} | |||||
// Move constructor | |||||
Matrix(Matrix&& m) { m_data = std::move(m.GetData()); } | |||||
// Constructor with size | |||||
Matrix(size_t rows, size_t cols) { | |||||
m_data.resize(rows); | |||||
for (auto& i : m_data) i.resize(cols, 0); | |||||
} | |||||
// reference-Getter of m_data | |||||
std::vector<std::vector<double>>& GetData() { return m_data; } | |||||
// Getter of m_data | |||||
const std::vector<std::vector<double>>& GetData() const { return m_data; } | |||||
size_t GetRows() const { return m_data.size(); } | |||||
size_t GetCols() const { | |||||
if (m_data.size() == 0) return 0; | |||||
return m_data[0].size(); | |||||
} | |||||
// Matrix multiplication operator | |||||
friend Matrix operator*(const Matrix& m1, const Matrix& m2); | |||||
// Inverse matrix using Gaussian elimination | |||||
static Matrix Inverse(const Matrix& m) { | |||||
int rows = m.GetRows(), cols = m.GetCols(); | |||||
if (rows != cols) | |||||
throw std::invalid_argument("Inverse is only for square matrices!"); | |||||
Matrix from(m), res(rows, rows); | |||||
std::vector<std::vector<double>>&datares = res.GetData(), | |||||
data = from.GetData(); | |||||
for (int i = 0; i < rows; ++i) datares[i][i] = 1; | |||||
for (int i = 0; i < rows; ++i) { | |||||
if (data[i][i] == 0.0) | |||||
throw std::invalid_argument("No inverse for this matrix!"); | |||||
for (int j = 0; j < rows; ++j) { | |||||
if (i != j) { | |||||
double ratio = data[j][i] / data[i][i]; | |||||
for (int k = 0; k < rows; ++k) | |||||
data[j][k] -= ratio * data[i][k]; | |||||
for (int k = 0; k < rows; ++k) | |||||
datares[j][k] -= ratio * datares[i][k]; | |||||
} | |||||
} | |||||
} | |||||
for (int i = 0; i < rows; ++i) | |||||
for (int j = 0; j < rows; ++j) datares[i][j] /= data[i][i]; | |||||
return res; | |||||
} | |||||
void print(std::ostream& out) const { | |||||
for (const auto& i : m_data) { | |||||
for (const auto& j : i) out << j << ' '; | |||||
out << '\n'; | |||||
} | |||||
} | |||||
}; | |||||
Matrix operator*(const Matrix& m1, const Matrix& m2) { | |||||
size_t rows = m1.GetRows(), cols = m2.GetCols(), mid = m1.GetCols(); | |||||
if (mid != m2.GetRows()) throw std::invalid_argument("Couldn't multiply!"); | |||||
Matrix res(rows, cols); | |||||
const std::vector<std::vector<double>>&data1 = m1.GetData(), | |||||
&data2 = m2.GetData(); | |||||
std::vector<std::vector<double>>& datares = res.GetData(); | |||||
for (size_t i = 0; i < rows; ++i) { | |||||
for (size_t j = 0; j < cols; ++j) { | |||||
datares[i][j] = 0; | |||||
for (size_t k = 0; k < mid; ++k) { | |||||
datares[i][j] += data1[i][k] * data2[k][j]; | |||||
} | |||||
} | |||||
} | |||||
return res; | |||||
} | |||||
inline std::ostream& operator<<(std::ostream& out, const Matrix& m) { | |||||
m.print(out); | |||||
return out; | |||||
} | |||||
int main() { | |||||
std::ifstream inputtxt("input.txt"); | |||||
std::ofstream outputtxt("output.txt"); | |||||
#ifdef DEBUG | |||||
std::istream& in = inputtxt; | |||||
std::ostream& out = std::cout; | |||||
#else | |||||
std::istream& in = inputtxt; | |||||
std::ostream& out = outputtxt; | |||||
#endif | |||||
out.precision(2); | |||||
int n, m; | |||||
in >> n >> m; | |||||
Matrix A(m, n + 1), Y(m, 1); | |||||
// input | |||||
std::vector<std::vector<double>>&a = A.GetData(), &y = Y.GetData(); | |||||
for (int i = 0; i < m; ++i) { | |||||
for (int j = 0; j < n + 1; ++j) { | |||||
if (j == 0) a[i][j] = 1; | |||||
if (j < n) | |||||
in >> a[i][j + 1]; | |||||
else | |||||
in >> y[i][0]; | |||||
} | |||||
} | |||||
out << "A:\n" << std::fixed << A << '\n'; | |||||
out << "b:\n" << std::fixed << Y << '\n'; | |||||
Matrix A_T(A, true), // A transpose | |||||
A_TA(std::move(A_T * A)), // A transpose multiplied by A | |||||
A_TA_inv( | |||||
std::move(Matrix::Inverse(A_TA))), // inverse of the previous one | |||||
A_TA_invA_T(std::move(A_TA_inv * A_T)), // multiplied by A transpose | |||||
ans(std::move(A_TA_invA_T * Y)); // answer x | |||||
out << "A_T*A:\n" << std::fixed << A_TA << '\n'; | |||||
out << "(A_T*A)_-1:\n" << std::fixed << A_TA_inv << '\n'; | |||||
out << "(A_T*A)_-1*A_T:\n" << std::fixed << A_TA_invA_T << '\n'; | |||||
out << "x:\n" << std::fixed << ans << '\n'; | |||||
} |