#include <cmath>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iostream>
#include <regex>
#include <set>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
class SegPoint
{
public:
explicit SegPoint(int n = 0) { arr.assign(n + 1, 0); }
void add(int l, int r, int addent)
{
for (int i = r + 1; i > 0; i -= lowbit(i)) {
arr[i] += addent;
}
for (int i = l; i > 0; i -= lowbit(i)) {
arr[i] -= addent;
}
}
int at(int index)
{
int ret = 0;
for (int i = index + 1; i < int(arr.size()); i += lowbit(i)) {
ret += arr[i];
}
return ret;
}
private:
int lowbit(int n) { return n & (-n); }
vector<int> arr;
};
double comb(int n, int m)
{
if (2 * m > n) {
m = n - m;
}
if (m < 0) {
return 0;
} else if (m == 0) {
return 1;
} else {
double ret = 1;
for (int i = 1; i <= m; ++i) {
ret = ret * (n - i + 1) / i;
}
return ret;
}
}
int gcd(int m, int n)
{
m = (m < 0) ? -m : m;
n = (n < 0) ? -n : n;
if (m < n) {
swap(m, n);
}
while (n) {
m = m % n;
swap(m, n);
}
return m;
}
int gcd(int m, int n, pair<int, int> &coef)
{
pair<int, int> vm(1, 0), vn(0, 1);
if (m < 0) {
m = -m;
vm.first = -1;
}
if (n < 0) {
n = -n;
vn.second = -1;
}
if (m < n) {
swap(m, n);
swap(vm, vn);
}
while (n) {
int k = m / n;
m = m % n;
vm.first -= k * vn.first;
vm.second -= k * vn.second;
swap(m, n);
swap(vm, vn);
}
// cout << "vm: " << vm.first << " " << vm.second << endl;
coef = vm;
return m;
}
int jacobi(int m, int n, bool first = true)
{
if (first) {
// check validity
if (n % 2 == 0 || n < 3) {
cout << "n should be odd number bigger than 1
";
return 0;
} else if (gcd(m, n) != 1) {
return 0;
}
}
int c = 1;
// mod n
m = ((m % n) + n) % n;
// divide all 2
int j2 = (n % 8 == 1 || n % 8 == 7) ? 1 : -1;
while (m % 2 == 0) {
c *= j2;
m /= 2;
}
if (m == 1) {
return c;
} else {
if (m % 4 == 3 && n % 4 == 3) {
c = -c;
}
return c * jacobi(n, m, false);
}
}
vector<int> sieve(int MaxP, int MaxN = 0)
{
vector<int> ret;
vector<bool> notPrime(MaxP + 1, false);
for (int i = 2; i <= MaxP; ++i) {
if (!notPrime[i]) {
ret.push_back(i);
}
for (int j = 0; j < (int)ret.size() && ret[j] * i <= MaxP; ++j) {
notPrime[ret[j] * i] = true;
if (i % ret[j] == 0) {
break;
}
}
}
if (MaxN > 0) {
ret.resize(MaxN);
}
return ret;
}
int power(int n, int e, const int mod = 0)
{
pair<int, int> coef;
// check validity
if (mod < 0) {
cout << "mod should be nonegative
";
return 0;
}
if (mod == 0 && e < 0) {
cout << "negative power of integer is forbidden, try pow() instead
";
return 0;
}
if (mod && e < 0) {
n = ((n % mod) + mod) % mod;
pair<int, int> coef;
if (gcd(n, mod, coef) != 1) {
cout << "the inverse of n does not exist as n is not coprime to "
"mod
";
return 0;
} else {
n = ((coef.first % mod) + mod) % mod;
e = -e;
}
}
long long ret = 1, lmod = mod, tmp = n;
for (int i = 1; i <= e; i <<= 1) {
if (i & e) {
ret = mod ? ret * tmp % lmod : ret * tmp;
}
tmp = mod ? tmp * tmp % lmod : tmp * tmp;
}
return int(ret);
}
double gpa(int score)
{
if (score >= 90) {
return 4;
} else if (score >= 87) {
return 3.9;
} else if (score >= 85) {
return 3.8;
} else if (score >= 83) {
return 3.7;
} else if (score >= 82) {
return 3.6;
} else if (score >= 80) {
return 3.5;
} else if (score >= 78) {
return 3.4;
} else if (score >= 76) {
return 3.3;
} else if (score >= 75) {
return 3.2;
} else if (score >= 74) {
return 3.1;
} else if (score >= 73) {
return 3.0;
} else if (score >= 72) {
return 2.9;
} else if (score >= 71) {
return 2.8;
} else if (score >= 69) {
return 2.7;
}
return -1e18;
}
void calcGpa()
{
ifstream fin;
fin.open("gpa.txt");
double credits = 0, sum = 0, c;
int s, cnt = 0;
while (fin >> c >> s) {
cnt++;
credits += c;
sum += c * gpa(s);
}
fin.close();
cout << cnt << " lessons
"
<< credits << " credits
"
<< "GPA = " << sum / credits << endl;
}
bool verify(char v = 'y')
{
string ansStr;
char ans;
cin >> ansStr;
ans = ansStr[0];
if (tolower(ans) == tolower(v)) {
return true;
}
}
void split(const string &s, vector<string> &tokens, const char &delim = ' ')
{
tokens.clear();
size_t lastPos = s.find_first_not_of(delim, 0);
size_t pos = s.find(delim, lastPos);
while (lastPos != string::npos) {
tokens.emplace_back(s.substr(lastPos, pos - lastPos));
lastPos = s.find_first_not_of(delim, pos);
pos = s.find(delim, lastPos);
}
}
void trim(string &str)
{
string blanks(" fv
");
str.erase(0, str.find_first_not_of(blanks));
str.erase(str.find_last_not_of(blanks) + 1);
}
bool bookify(const string &filename)
{
cout << "The following file is to be bookified:
" << filename
<< "
Make sure it is encoded in UTF-8 (y/n): ";
if (!verify()) {
return false;
}
string tmp;
cout << "Chapter regular expression (第.{1,20}章):
";
cin >> tmp;
regex chaReg('^' + tmp);
vector<string> commas;
cout << "Each line must end with specific commas (。!?”」…*.!?):
";
cin >> tmp;
regex endReg('[' + tmp + "]$");
int nSpaces;
cout << "Each line must begin with some number of spaces: ";
cin >> nSpaces;
string outFile = filename;
outFile.insert(filename.find_last_of("."), "_out");
cout << "Output file would be:
" << outFile
<< "
Confirm or type a new one (c/t): ";
if (!verify('c')) {
cout << "Type a new one:
";
cin >> outFile;
}
ifstream fin;
fin.open(filename.c_str());
if (!fin.is_open()) {
cout << "Fail to open file
";
return false;
}
ofstream fout;
fout.open(outFile.c_str());
int chapCnt = 0;
bool isStart = true;
while (fin.good()) {
getline(fin, tmp);
trim(tmp);
if (regex_search(tmp, chaReg)) {
tmp = regex_replace(tmp, chaReg, "");
trim(tmp);
if (chapCnt) {
fout << endl << endl;
}
fout << "第" << ++chapCnt << "章 " << tmp << endl << endl;
cout << "第" << chapCnt << "章 " << tmp << endl;
isStart = true;
} else {
if (isStart) {
for (int i = 0; i < nSpaces; ++i) {
fout << " ";
}
}
if (regex_search(tmp, endReg)) {
fout << tmp << endl;
isStart = true;
} else {
fout << tmp;
isStart = false;
}
}
}
fin.close();
fout.flush();
fout.close();
return true;
}
bool prepareForEpub(const string &filename)
{
cout << "The following file is to be bookified:
" << filename
<< "
Make sure it is encoded in UTF-8 (y/n): ";
if (!verify()) {
return false;
}
ifstream conf;
conf.open("epub.conf");
if (!conf.is_open()) {
cout << "Fail to open configure file
";
return false;
}
string tmp;
conf >> tmp;
regex volReg(tmp);
conf >> tmp;
regex chaReg(tmp);
conf >> tmp;
regex endReg(tmp);
int nSpaces;
conf >> nSpaces;
conf.close();
ifstream fin;
fin.open(filename.c_str());
if (!fin.is_open()) {
cout << "Fail to open file
";
return false;
}
string outFile = filename;
outFile.insert(filename.find_last_of("."), "_out");
cout << "Output file would be:
" << outFile << endl;
ofstream fout;
fout.open(outFile.c_str());
bool isStart = true;
while (fin.good()) {
getline(fin, tmp);
trim(tmp);
if (regex_search(tmp, volReg)) {
fout << "# " << tmp << endl << endl;
isStart = true;
} else if (regex_search(tmp, chaReg)) {
fout << "## " << tmp << endl << endl;
isStart = true;
} else {
if (isStart) {
for (int i = 0; i < nSpaces; ++i) {
fout << " ";
}
}
if (regex_search(tmp, endReg)) {
fout << tmp << endl << endl;
isStart = true;
} else {
fout << tmp;
isStart = false;
}
}
}
fin.close();
fout.flush();
fout.close();
return true;
}
int w(int n)
{
int ret = 0;
for (int m = 1; m <= n; m <<= 1) {
if (m & n) {
ret++;
}
}
return ret;
}
int stirling1(int p, int k) {
if (p < k || k < 0) {
cout << "p >= k >= 0
";
return 0;
} else if (k == p) {
return 1;
} else if (k == 0) {
return 0;
} else {
return stirling1(p-1,k-1) + (p-1)*stirling1(p-1,k);
}
}
int stirling2(int p, int k) {
if (p < k || k < 0) {
cout << "p >= k >= 0
";
return 0;
} else if (k == p) {
return 1;
} else if (k == 0) {
return 0;
} else {
return stirling2(p-1,k-1) + k*stirling2(p-1,k);
}
}
class Permutation
{
public:
Permutation() {}
bool input() {
data.clear();
int n;
cin >> n;
if (n <= 1) {
return false;
} else {
vector<bool> flag(n, false);
for (int i = 0, t; i < n; ++i) {
cin >> t;
if (t < 1 || t > n || flag[t-1]) {
data.clear();
return false;
} else {
flag[t-1] = true;
data.emplace_back(t-1);
}
}
return true;
}
}
int length() const {
return data.size();
}
Permutation operator* (const Permutation& sig) const {
if (length() != sig.length()) {
cout << "Illegal to multiple two permutation of different order
";
return Permutation();
}
Permutation ret = sig;
for (int i = 0; i < length(); ++i) {
ret[i] = data[sig[i]];
}
return ret;
}
bool operator== (const Permutation& sig) const {
if (length() != sig.length()) {
return false;
} else {
for (int i = 0; i < length(); ++i) {
if (data[i] != sig[i]) {
return false;
}
}
return true;
}
}
void print() {
int n = length();
vector<bool> flag(n, false);
for (int i = 0; i < n; ++i) {
if (!flag[i]) {
cout << "(" << i+1;
int t = data[i];
while (t != i) {
flag[t] = true;
cout << " " << t+1;
t = data[t];
}
cout << ")";
}
}
cout << endl;
}
protected:
const int& operator[] (int index) const {
return data.at(index);
}
int& operator[] (int index) {
return data[index];
}
private:
vector<int> data; // 0 indexed
};
class Group
{
public:
void clear() {
data.clear();
}
void addElement(const Permutation& sig) {
data.emplace_back(sig);
}
void inputGenerator() {
data.clear();
while (1) {
Permutation sig;
if (!sig.input()) {
return;
} else {
data.emplace_back(sig);
}
}
}
void setIterNumber(int n) {
nIter = n;
}
void startIter() {
for (int i = 0; i < nIter; ++i) {
int n = data.size();
Permutation sig = data[rand()%n] * data[rand()%n];
bool found = false;
for (auto& tau: data) {
if (tau == sig) {
found = true;
break;
}
}
if (!found) {
data.emplace_back(sig);
}
}
}
void print() {
for (auto& sig: data) {
sig.print();
}
}
private:
vector<Permutation> data;
int nIter;
};
int main() {
srand((unsigned)time(NULL));
Group d;
d.setIterNumber(100);
d.inputGenerator();
d.startIter();
d.print();
}