Gym - 102501D Gnalcats

https://codeforces.com/gym/102501/problem/D

题意

给两种栈操作判断是否相等,如果两个操作都fail,也认为相等

Solution

模拟,每个氨基酸一个hash值。通过判断最后栈元素是否对应hash相等,判断操作是否相等

#include <cstdio>
#include <stack>
#include <set>
#include <cmath>
#include <map>
#include <time.h>
#include <vector>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
//#include <memory.h>
#include <cstdlib>
#include <queue>
#include <iomanip>
#include <cassert>
#include <unordered_map>
#define P pair<int, int>
#define LL long long
#define LD long double
#define PLL pair<LL, LL>
#define mset(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for (int i = a; i < b; i++)
#define PI acos(-1.0)
#define random(x) rand() % x
#define debug(x) cout << #x << " " << x << "\n"
using namespace std;
const int inf = 0x3f3f3f3f;
const LL __64inf = 0x3f3f3f3f3f3f3f3f;
#ifdef DEBUG
const int MAX = 2e3 + 50;
#else
const int MAX = 1e6 + 50;
#endif
const int mod = 1e9 + 7;
void file_read() {
#ifdef DEBUG
	freopen("in", "r", stdin);
	// freopen("out", "w", stdout);
#endif
}

#define ULL unsigned long long

struct DNA
{
	struct Node
	{
		int l, r;
		unsigned LL val;
		Node(){}
		Node(int l, int r, unsigned LL val) : l(l), r(r), val(val) {}
		bool complex() const {
			return l and r;
		}
	}tr[MAX];
	stack<int> stk;
	int tot;
	int num;
	DNA() : tot(1), num(1) {
		for(int i = 1; i <= (int)1e5; i++) {
			tr[tot] = Node(0, 0, num++);
			stk.push(tot);
			tot++;
		}
	}
	ULL hash(int u, int v) {
		ULL base = 131;
		return tr[u].val * base + tr[v].val;
	}
	bool op_C() {
		auto u = stk.top();
		tr[tot] = tr[u];
		stk.push(tot);
		tot++;
		return true;	
	}
	bool op_D() {
		stk.pop();
		return true;
	}
	bool op_L() {
		auto u = stk.top(); stk.pop();
		if(!tr[u].complex())  
			return false;	
		// tr[tot] = tr[tr[u].l];
		// stk.push(tot);
		stk.push(tr[u].l);
		return true;
	}
	bool op_P() {
		auto u = stk.top(); stk.pop();
		auto v = stk.top(); stk.pop();
		tr[tot] = Node(u, v, hash(u, v));
		stk.push(tot);
		tot++;
		return true;
	}
	bool op_R() {
		auto u = stk.top(); stk.pop();
		if(!tr[u].complex()) 
			return false;
		// tr[tot] = tr[tr[u].r];
		// stk.push(tot++);
		stk.push(tr[u].r);
		return true;
	}
	bool op_S() {
		auto u = stk.top(); stk.pop();
		auto v = stk.top(); stk.pop();
		stk.push(u);
		stk.push(v);
		return true;
	}
	bool op_U() {
		auto u = stk.top(); stk.pop();
		if(!tr[u].complex()) 
			return false;
		stk.push(tr[u].r);
		stk.push(tr[u].l);
		return true;
	}
	bool op(const string &s) {
		bool res = true;
		for(auto c : s) {
			switch (c)
			{
			case 'C':res &= op_C(); break;
			case 'D':res &= op_D(); break;
			case 'L':res &= op_L(); break;
			case 'P':res &= op_P(); break;
			case 'R':res &= op_R(); break;
			case 'S':res &= op_S(); break;
			case 'U':res &= op_U(); break;
			default:
				break;
			}
		}
		return res ;
	}
};

DNA A, B;
int main() {
	file_read();
	string s, t;
	cin >> s >> t;
	A = DNA();
	B = DNA();
	bool a = A.op(s);
	bool b = B.op(t);
	if(a ^ b) {
		puts("False");
		return 0;
	}
	if(!a and !b) {
		puts("True");
		return 0;
	}
	while(!A.stk.empty() and !B.stk.empty()) {
		auto u = A.stk.top(); A.stk.pop();
		auto v = B.stk.top(); B.stk.pop();
		if(A.tr[u].val != B.tr[v].val) {
			puts("False");
			return 0;
		}
	}
	if(!A.stk.empty() || !B.stk.empty()) {
		puts("False");
		return 0;
	}
	puts("True");
	return 0;
}

Gym - 102501J

https://codeforces.com/gym/102501/problem/J

题意

给一个树的中序遍历序列,判断有多少满足类似小根堆的树,$n<=1e5$

Solution

  • 直接dp一定会超时
  • 考虑根可能在的位置,即当前最小元素的位置
  • 考虑选这些元素为根会有哪些树,就可以发现当前的最小元素将序列分成子段,当前元素作为根的种类数是卡特兰数
  • 因此递归解决这个问题,每次用最小元素分割当前序列,最后其实就是一些卡特兰数的乘积
  • 用单调栈会更优美一点
#include <cstdio>
#include <stack>
#include <set>
#include <cmath>
#include <map>
#include <time.h>
#include <vector>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
//#include <memory.h>
#include <cstdlib>
#include <queue>
#include <iomanip>
#include <cassert>
#include <unordered_map>
#define P pair<int, int>
#define LL long long
#define LD long double
#define PLL pair<LL, LL>
#define mset(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for (int i = a; i < b; i++)
#define PI acos(-1.0)
#define random(x) rand() % x
#define debug(x) cout << #x << " " << x << "\n"
using namespace std;
const int inf = 0x3f3f3f3f;
const LL __64inf = 0x3f3f3f3f3f3f3f3f;
#ifdef DEBUG
const int MAX = 2e3 + 50;
#else
const int MAX = 2e6 + 500;
#endif
const int mod = 1e9 + 7;
void file_read() {
#ifdef DEBUG
	freopen("in", "r", stdin);
	// freopen("out", "w", stdout);
#endif
}


int a[MAX];
LL fact[MAX];
LL inv[MAX];
map<int, vector<int>> pos;
LL qpow(LL x, LL n) {
	LL res = 1;
	while(n) {
		if(n & 1) {
			res = res * x % mod;
		}
		x = x * x % mod;
		n >>= 1;
	}
	return res;
}
LL f(LL x) {
	return fact[2*x] * inv[x] % mod * inv[x+1] % mod;
}

int main() {
	file_read();
	int n; 
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	fact[0] = 1;
	for(int i = 1; i < MAX; i++) fact[i] = 1LL * fact[i-1] * i % mod;
	inv[MAX-1] = qpow(fact[MAX-1], mod-2);
	for(int i = MAX-2; i >= 1; i--) inv[i] = 1LL * (i+1) * inv[i+1] % mod;
	inv[0] = 1;
	LL res = 1;
	stack<int> stk;
	for(int i = 1; i <= n; i++) {
		if(stk.empty()) {
			stk.push(a[i]);
			continue;
		}
		int cnt = 0;
		int cur = inf;
		while(!stk.empty() and stk.top() > a[i]) {
			if(stk.top() == cur) {
				cnt++;
			}
			else {
				res = res * f(cnt) % mod;
				cnt = 1;
				cur = stk.top();
			}
			stk.pop();
		}
		stk.push(a[i]);
		res = res * f(cnt) % mod;
	}
	int cur = inf;
	int cnt = 0;
	while(!stk.empty()) {
		if(stk.top() == cur) {
			cnt++;
		}
		else {
			res = res * f(cnt) % mod;
			cur = stk.top();
			cnt = 1;
		}
		stk.pop();
	}
	res = res * f(cnt ) % mod;
	printf("%lld\n", res);
}