@@ -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'; | |||
} |