-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
43e46c4
commit 4e0b661
Showing
12 changed files
with
741 additions
and
163 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
105 changes: 105 additions & 0 deletions
105
src/Another Substring Query Problem/anothersubstringqueryproblem.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// https://github.com/stevenhalim/cpbook-code/blob/master/ch6/sa_lcp.cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
|
||
typedef pair<int, int> ii; | ||
typedef vector<int> vi; | ||
|
||
class SuffixArray { | ||
private: | ||
vi RA; | ||
|
||
void countingSort(int k) { | ||
int maxi = max(300, n); | ||
vi c(maxi, 0); | ||
for (int i = 0; i < n; ++i) | ||
++c[i+k < n ? RA[i+k] : 0]; | ||
for (int i = 0, ss = 0; i < maxi; ++i) { | ||
int t = c[i]; c[i] = ss; ss += t; | ||
} | ||
vi temp(n); | ||
for (int i = 0; i < n; ++i) | ||
temp[c[SA[i]+k < n ? RA[SA[i]+k] : 0]++] = SA[i]; | ||
swap(SA, temp); | ||
} | ||
|
||
void constructSA() { | ||
SA.resize(n); | ||
iota(SA.begin(), SA.end(), 0); | ||
RA.resize(n); | ||
for (int i = 0; i < n; ++i) RA[i] = T[i]; | ||
for (int k = 1; k < n; k <<= 1) { | ||
countingSort(k); | ||
countingSort(0); | ||
vi temp(n); | ||
int r = 0; | ||
temp[SA[0]] = r; | ||
for (int i = 1; i < n; ++i) | ||
temp[SA[i]] = | ||
((RA[SA[i]] == RA[SA[i-1]]) && (RA[SA[i]+k] == RA[SA[i-1]+k])) ? r : ++r; | ||
swap(RA, temp); | ||
if (RA[SA[n-1]] == n-1) break; | ||
} | ||
} | ||
|
||
public: | ||
string T; | ||
const int n; | ||
vi SA; | ||
|
||
SuffixArray(string initialT) : T(initialT), n(initialT.size()) { | ||
constructSA(); | ||
} | ||
|
||
ii stringMatching(string P) { | ||
int m = (int)P.size(); | ||
int lo = 0, hi = n-1; | ||
while (lo < hi) { | ||
int mid = (lo+hi) / 2; | ||
int res = T.compare(SA[mid], m, P); | ||
(res >= 0) ? hi = mid : lo = mid+1; | ||
} | ||
if (T.compare(SA[lo], m, P) != 0) return {-1, -1}; | ||
ii ans; ans.first = lo; | ||
hi = n-1; | ||
while (lo < hi) { | ||
int mid = (lo+hi) / 2; | ||
int res = T.compare(SA[mid], m, P); | ||
(res > 0) ? hi = mid : lo = mid+1; | ||
} | ||
if (T.compare(SA[hi], m, P) != 0) --hi; | ||
ans.second = hi; | ||
return ans; | ||
} | ||
}; | ||
|
||
int main() { | ||
ios_base::sync_with_stdio(false); | ||
cin.tie(NULL); | ||
cout.tie(NULL); | ||
|
||
int n, lo, hi, k; | ||
unordered_map<string, vi> h, q; | ||
string p, s, t; | ||
getline(cin, s); | ||
cin >> n; | ||
int z[n]; | ||
ii ans; | ||
for (int i = 0; i < n; i++) { | ||
cin >> t >> k; h[t].push_back(k); q[t].push_back(i); | ||
} | ||
s += char(0); | ||
SuffixArray sa(s); | ||
for (auto& [t, vv] : h) { | ||
ans = sa.stringMatching(t); | ||
lo = ans.first; hi = ans.second; | ||
vi v; | ||
if (lo+1 || hi+1) { | ||
for (int j = lo; j <= hi; j++) v.push_back(sa.SA[j]); | ||
sort(v.begin(), v.end()); | ||
} | ||
for (int i = 0; i < h[t].size(); i++) z[q[t][i]] = (v.size() < h[t][i]) ? -1 : v[h[t][i]-1]+1; | ||
} | ||
for (int i : z) cout << i << '\n'; | ||
return 0; | ||
} |
58 changes: 58 additions & 0 deletions
58
src/Another Substring Query Problem/anothersubstringqueryproblem.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
def smm(s, pp): | ||
def suffix_array_construction(s): | ||
n = len(s) | ||
sa = list(range(n)) | ||
ra = [ord(s[i]) for i in range(n)] | ||
k, maxi = 1, max(300, n) | ||
while k < n: | ||
for kk in [k, 0]: | ||
c = [0]*maxi | ||
for i in range(n): c[ra[i+kk] if i+kk<n else 0] += 1 | ||
ss, temp = 0, [0]*n | ||
for i in range(maxi): t = c[i]; c[i] = ss; ss += t | ||
for i in range(n): | ||
idx = ra[sa[i]+kk] if sa[i]+kk < n else 0 | ||
temp[c[idx]] = sa[i] | ||
c[idx] += 1 | ||
sa = temp | ||
temp, r = [0]*n, 0 | ||
temp[sa[0]] = r | ||
for i in range(1, n): | ||
r += ra[sa[i]] != ra[sa[i-1]] or ra[sa[i]+k] != ra[sa[i-1]+k] | ||
temp[sa[i]] = r | ||
ra = temp | ||
if ra[sa[n-1]] == n-1: break | ||
k *= 2 | ||
return sa | ||
s += '\0' | ||
sa = suffix_array_construction(s) | ||
n = len(s) | ||
matches = [] | ||
for p in pp: | ||
m, lo, hi = len(p), 0, n-1 | ||
while lo < hi: | ||
mid = (lo+hi)//2 | ||
if s[sa[mid]:sa[mid]+m] >= p: hi = mid | ||
else: lo = mid+1 | ||
if s[sa[lo]:sa[lo]+m] != p: matches.append([]); continue | ||
l, hi = lo, n-1 | ||
while lo < hi: | ||
mid = (lo+hi)//2 | ||
if s[sa[mid]:sa[mid]+m] > p: hi = mid | ||
else: lo = mid+1 | ||
matches.append(sorted(sa[i] for i in range(l, hi - (s[sa[hi]:sa[hi]+m] != p) + 1))) | ||
return matches | ||
|
||
import sys; input = sys.stdin.readline; from array import * | ||
s = input().strip(); h = {}; q = {}; n = int(input()); z = array('i', [0]*n) | ||
for i in range(n): | ||
t, k = input().split(); k = int(k) | ||
if t not in h: h[t] = []; q[t] = [] | ||
h[t].append(k); q[t].append(i) | ||
a = [*h]; p = smm(s, a) | ||
for i in range(len(a)): | ||
t = a[i] | ||
for j in range(len(h[t])): | ||
if h[t][j] > len(p[i]): z[q[t][j]] = -1 | ||
else: z[q[t][j]] = p[i][h[t][j]-1]+1 | ||
print(*z) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
N,*A=map(int,open(W:=0).read().split());V=[Z:=0]*N | ||
for i in range(N):t=i<N/2;V[A[i]-1]=1-t;Z+=(2*t-1)*A[i]+i*t | ||
for i in V:Z-=(W:=W+i)*(1-i) | ||
print(Z) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
def add(word, verdict): | ||
temp = {} | ||
for idx in range(len(word)): | ||
if verdict[idx] != 'X': | ||
if word[idx] not in temp: | ||
temp[word[idx]] = 0 | ||
temp[word[idx]] += 1 | ||
for k in temp: | ||
if k not in freq: | ||
freq[k] = set(range(len(word))) | ||
freq[k] -= set(range(temp[k])) | ||
for idx in range(len(word)): | ||
if verdict[idx] == 'X': | ||
if word[idx] in temp: | ||
freq[word[idx]] = {temp[word[idx]]} | ||
else: | ||
freq[word[idx]] = {0} | ||
for idx in range(len(word)): | ||
if verdict[idx] == '/': | ||
if word[idx] not in kb: | ||
kb[word[idx]] = set(range(len(word))) | ||
kb[word[idx]] -= {idx} | ||
for idx in range(len(word)): | ||
if verdict[idx] == 'O': | ||
if word[idx] not in kb2: | ||
kb2[word[idx]] = set() | ||
kb2[word[idx]].add(idx) | ||
for idx in range(len(word)): | ||
if verdict[idx] == 'X' and word[idx] not in kb and word[idx] not in kb2: | ||
illegal.add(word[idx]) | ||
|
||
def verify(check): | ||
kb2c = {} | ||
for k in kb2: | ||
kb2c[k] = kb2[k].copy() | ||
for idx in range(len(check)): | ||
if check[idx] in illegal: | ||
return | ||
try: | ||
kb2c[check[idx]].remove(idx) | ||
if not kb2c[check[idx]]: | ||
del kb2c[check[idx]] | ||
except: | ||
if check[idx] in kb and idx not in kb[check[idx]]: | ||
return | ||
freq2 = {} | ||
for k in check: | ||
if k not in freq2: | ||
freq2[k] = 0 | ||
freq2[k] += 1 | ||
for k in freq2: | ||
if k in freq and freq2[k] not in freq[k]: | ||
return | ||
for k in freq: | ||
if k in freq2: | ||
if min(freq[k]) > freq2[k]: | ||
return | ||
elif min(freq[k]) > 0: | ||
return | ||
if not kb2c: | ||
possible.append(check) | ||
|
||
from random import * | ||
N = int(input()); W = [input() for _ in range(N)] | ||
kb, kb2, freq = {}, {}, {}; illegal = set() | ||
while W: | ||
print(word:=choice(W)); W.remove(word); verdict = input(); add(word, verdict) | ||
if verdict == 'O'*5: exit(0) | ||
possible = [] | ||
for w in W: verify(w) | ||
W = possible |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Testing tool for the Ordla problem | ||
# | ||
# Usage: | ||
# | ||
# python3 testing_tool.py [-f input_file] <program> | ||
# | ||
# If the -f parameter is not specified, sample 1 is used. Otherwise, | ||
# an input file is needed. The file starts with the number of words | ||
# in the dictionary, followed by the words in the dictionary, one per | ||
# line. For example: | ||
# | ||
# 5 | ||
# tolva | ||
# ordla | ||
# stoll | ||
# skjar | ||
# skoli | ||
|
||
# You can compile and run your solution as follows. | ||
# - You may have to replace 'python3' by just 'python'. | ||
# - On Windows, you may have to to replace '/' by '\'. | ||
|
||
# C++: | ||
# g++ solution.cpp | ||
# python3 testing_tool.py ./a.out | ||
|
||
# Java | ||
# javac solution.java | ||
# python3 testing_tool.py java solution | ||
|
||
# Python3 | ||
# python3 testing_tool.py python3 ./solution.py | ||
|
||
# The tool is provided as-is, and you should feel free to make | ||
# whatever alterations or augmentations you like to it. | ||
# | ||
# The tool attempts to detect and report common errors, but it | ||
# is not guaranteed that a program that passes the testing tool | ||
# will be accepted. | ||
# | ||
|
||
import argparse | ||
import subprocess | ||
import sys | ||
import traceback | ||
import string | ||
import random | ||
from collections import Counter | ||
|
||
|
||
def write(p, line): | ||
assert p.poll() is None, 'Program terminated early' | ||
print('Write: {}'.format(line), flush=True) | ||
p.stdin.write('{}\n'.format(line)) | ||
p.stdin.flush() | ||
|
||
|
||
def read(p): | ||
assert p.poll() is None, 'Program terminated early' | ||
line = p.stdout.readline().strip() | ||
assert line != '', 'Read empty line or closed output pipe. Make sure that your program started successfully.' | ||
print('Read: %s' % line, flush=True) | ||
return line | ||
|
||
|
||
parser = argparse.ArgumentParser(description='Testing tool for the Ordla problem') | ||
parser.add_argument('-f', dest='inputfile', metavar='inputfile', default=None, type=argparse.FileType('r'), | ||
help='Custom input file (defaults to sample 1)') | ||
parser.add_argument('program', nargs='+', help='Your solution') | ||
|
||
args = parser.parse_args() | ||
guesses = 0 | ||
|
||
if args.inputfile is not None: | ||
# Read the input file | ||
with args.inputfile as f: | ||
n = int(f.readline().strip()) | ||
assert 1 <= n <= 500, 'n must be between 1 and 500' | ||
words = [] | ||
for i in range(n): | ||
word = f.readline().strip() | ||
assert len(word) == 5, 'Each word must consist of 5 letters' | ||
assert set(word) <= set(string.ascii_lowercase), 'Each word must consist of lowercase English letters' | ||
words.append(word) | ||
assert f.readline() == '', 'Extra data at end of input file' | ||
else: | ||
words = [ | ||
'tolva', | ||
'ordla', | ||
'stoll', | ||
'skjar', | ||
'skoli', | ||
] | ||
|
||
correct_word = random.choice(words) | ||
print('Hidden word: {}'.format(correct_word), flush=True) | ||
|
||
with subprocess.Popen(" ".join(args.program), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, | ||
universal_newlines=True) as p: | ||
try: | ||
write(p, '%d' % len(words)) | ||
for word in words: | ||
write(p, word) | ||
while True: | ||
guess = read(p) | ||
assert len(guess) == 5, 'Each guess must consist of 5 letters' | ||
assert set(guess) <= set(string.ascii_lowercase), 'Each guess must consist of lowercase English letters' | ||
assert guess in words, 'Each guess must be from the dictionary' | ||
guesses += 1 | ||
|
||
rem = Counter(correct_word) | ||
pattern = ['X']*5 | ||
for i, c in enumerate(guess): | ||
if correct_word[i] == c: | ||
pattern[i] = 'O' | ||
rem[c] -= 1 | ||
elif rem[c] >= 1: | ||
pattern[i] = '/' | ||
rem[c] -= 1 | ||
|
||
write(p, ''.join(pattern)) | ||
|
||
if guess == correct_word: | ||
assert p.stdout.readline() == '', 'Printed extra data after finding hidden word' | ||
assert p.wait() == 0, 'Did not exit cleanly after finishing' | ||
break | ||
if guesses == 10000: | ||
sys.stdout.write('Solution has guessed {} times without finding the hidden word. Is it stuck in a loop?\n'.format(guesses)) | ||
sys.stdout.flush() | ||
|
||
except: | ||
traceback.print_exc() | ||
finally: | ||
sys.stdout.flush() | ||
sys.stderr.flush() | ||
sys.stdout.write('Solution found the word in {} guesses, exit code: {}\n'.format(guesses, p.wait())) | ||
sys.stdout.flush() |
Oops, something went wrong.