Submission #209562

# Submission time Handle Problem Language Result Execution time Memory
209562 2020-03-14T15:26:37 Z E869120 Security Gate (JOI18_security_gate) C++14
0 / 100
648 ms 1048580 KB
#include <iostream>
#include <string>
#include <cassert>
#include <algorithm>
using namespace std;

const int MAX_N = 104;

// 73 点解法
long long mod = 1000000007;
long long N; string S;

int dpl[MAX_N][MAX_N][MAX_N], sl[MAX_N][MAX_N][MAX_N];
int dpr[MAX_N][MAX_N][MAX_N], sr[MAX_N][MAX_N][MAX_N];
int dp1[MAX_N][MAX_N][MAX_N][MAX_N];
int dp2[MAX_N][MAX_N][MAX_N * 2][MAX_N];

void all_init() {
	for (int i = 0; i < MAX_N; i++) {
		for (int j = 0; j < MAX_N; j++) {
			for (int k = 0; k < MAX_N; k++) {
				dpl[i][j][k] = 0; sl[i][j][k] = 0;
				dpr[i][j][k] = 0; sr[i][j][k] = 0;
				for (int l = 0; l < MAX_N * 1; l++) dp1[i][j][l][k] = 0;
				for (int l = 0; l < MAX_N * 2; l++) dp2[i][j][l][k] = 0;
			}
		}
	}
}

void solve_1(int pos) {
	dp1[pos][pos][0][0] = 1;
	for (int i = pos; i < N; i++) {
		for (int j = 0; j < N; j++) {
			for (int k = 0; k < N; k++) {
				if (dp1[pos][i][j][k] == 0) continue;
				if ((S[i] == '(' || S[i] == 'x') && j >= 0) {
					dp1[pos][i + 1][j + 1][max(j + 1, k)] += dp1[pos][i][j][k];
					if (dp1[pos][i + 1][j + 1][max(j + 1, k)] >= mod) dp1[pos][i + 1][j + 1][max(j + 1, k)] -= mod;
				}
				if ((S[i] == ')' || S[i] == 'x') && j >= 1) {
					dp1[pos][i + 1][j - 1][max(j - 1, k)] += dp1[pos][i][j][k];
					if (dp1[pos][i + 1][j - 1][max(j - 1, k)] >= mod) dp1[pos][i + 1][j - 1][max(j - 1, k)] -= mod;
				}
			}
		}
	}
	for (int i = pos; i <= N; i++) {
		for (int j = 0; j <= N; j++) {
			for (int k = N; k >= 0; k--) {
				dp1[pos][i][j][k] += dp1[pos][i][j][k + 1];
				if (dp1[pos][i][j][k] >= mod) dp1[pos][i][j][k] -= mod;
			}
		}
	}
}

void solve_2(int pos) {
	dp2[pos][pos][N][0] = 1;
	for (int i = pos; i < N; i++) {
		for (int j = 0; j <= N * 2; j++) {
			for (int k = 0; k < N; k++) {
				if (dp2[pos][i][j][k] == 0) continue;
				if (S[i] == '(' || S[i] == 'x') {
					int val = max(j + 1 - (int)N, k);
					dp2[pos][i + 1][j + 1][val] += dp2[pos][i][j][k];
					if (dp2[pos][i + 1][j + 1][val] >= mod) dp2[pos][i + 1][j + 1][val] -= mod;
				}
				if (S[i] == ')' || S[i] == 'x') {
					int val = max(j - 1 - (int)N, k);
					dp2[pos][i + 1][j - 1][val] += dp2[pos][i][j][k];
					if (dp2[pos][i + 1][j - 1][val] >= mod) dp2[pos][i + 1][j - 1][val] -= mod;
				}
			}
		}
	}
}

void init() {
	// 正しいカッコ列の数を計算する(左側から)
	dpl[0][0][0] = 1;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			for (int k = 0; k < N; k++) {
				if (dpl[i][j][k] == 0) continue;
				if ((S[i] == '(' || S[i] == 'x') && j >= 0) {
					dpl[i + 1][j + 1][max(j + 1, k)] += dpl[i][j][k];
					dpl[i + 1][j + 1][max(j + 1, k)] %= mod;
				}
				if ((S[i] == ')' || S[i] == 'x') && j >= 1) {
					dpl[i + 1][j - 1][max(j - 1, k)] += dpl[i][j][k];
					dpl[i + 1][j - 1][max(j - 1, k)] %= mod;
				}
			}
		}
	}

	// 正しいカッコ列の数を計算する(右側から)
	dpr[N][0][0] = 1;
	for (int i = N - 1; i >= 0; i--) {
		for (int j = 0; j < N; j++) {
			for (int k = 0; k < N; k++) {
				if (dpr[i + 1][j][k] == 0) continue;
				if ((S[i] == ')' || S[i] == 'x') && j >= 0) {
					dpr[i][j + 1][max(j + 1, k)] += dpr[i + 1][j][k];
					dpr[i][j + 1][max(j + 1, k)] %= mod;
				}
				if ((S[i] == '(' || S[i] == 'x') && j >= 1) {
					dpr[i][j - 1][max(j - 1, k)] += dpr[i + 1][j][k];
					dpr[i][j - 1][max(j - 1, k)] %= mod;
				}
			}
		}
	}

	// 累積和を計算する
	for (int i = 0; i <= N; i++) {
		for (int j = 0; j <= N; j++) {
			for (int k = 0; k <= N; k++) sl[i][j][k] = dpl[i][j][k];
			for (int k = N; k >= 0; k--) { sl[i][j][k] += sl[i][j][k + 1]; sl[i][j][k] %= mod; }
		}
	}
	for (int i = 0; i <= N; i++) {
		for (int j = 0; j <= N;j++) {
			for (int k = 0; k <= N; k++) sr[i][j][k] = dpr[i][j][k];
			for (int k = N; k >= 0; k--) { sr[i][j][k] += sr[i][j][k + 1]; sr[i][j][k] %= mod; }
		}
	}

	for (int i = 0; i <= N; i++) {
		solve_1(i);
		solve_2(i);
	}
}

long long solve2(int maxval, int dep) {
	int goal = maxval - dep / 2;
	if (goal >= dep - 1) {
		long long ans = 0;
		for (int i = 0; i <= N - 1; i++) {
			if (S[i] == ')') continue;
			long long v1 = sl[i][dep - 1][0];
			long long v2 = dpr[i + 1][0][maxval - dep];
			ans += v1 * v2;
			ans %= mod;
		}
		return ans;
	}
	else {
		long long ans = 0;
		for (int i = 0; i <= N - 1; i++) {
			if (S[i] == ')') continue;
			long long v1 = dpr[i + 1][0][maxval - dep];
			for (int j = 0; j < i; j++) {
				if (S[j] == ')') continue;
				long long v2 = sl[j][goal][0];
				long long v3 = (dp1[j + 1][i][dep - 2 - goal][0] - dp1[j + 1][i][dep - 2 - goal][goal] + mod) % mod;
				ans += v1 * (v2 * v3 % mod) % mod;
				ans %= mod;
			}
		}
		return ans;
	}
}

long long solve4(int maxv, int dep) {
	long long ans = 0;
	int bo = max({ 0, dep, maxv });
	int cl_border = (bo + 1) / 2;
	int cr_border = (bo + 1) / 2 + dep / 2;
	if (cl_border * 2 + maxv + abs(maxv - dep) + min(0, cr_border - dep) * 2 > N) return 0;

	for (int i = 0; i <= N - 1; i++) {
		if (S[i] == '(') continue;
		long long v1 = sl[i][0][cl_border];
		for (int j = i + 1; j <= N - 1; j++) {
			if (S[j] == ')') continue;
			long long v2 = dp2[i + 1][j][dep + N][maxv + 1];
			long long v3 = sr[j + 1][0][cr_border - dep];
			ans += v1 * (v2 * v3 % mod) % mod;
			ans %= mod;
		}
	}
	return ans;
}

int main() {
	cin >> N >> S; assert(N <= 100);
	if (S.size() % 2 == 1) { cout << "0" << endl; return 0; }
	init();

	// パターン 1(カッコ列が正しい)
	long long ans1 = sl[N][0][0];

	// パターン 2(dep > 0、左側が全体)
	long long ans2 = 0;
	for (int i = N; i >= 1; i -= 2) {
		for (int j = i; j <= N; j++) {
			if (2 * j - i > N) continue;
			ans2 += solve2(j, i);
			ans2 %= mod;
		}
	}

	// パターン 4(どちらも全体ではない)
	long long ans4 = 0;
	for (int i = -1; i <= N; i++) {
		for (int j = -N; j <= N; j += 2) {
			ans4 += solve4(i, j);
			ans4 %= mod;
		}
	}

	// 折り返す
	reverse(S.begin(), S.end());
	for (int i = 0; i < S.size(); i++) {
		if (S[i] == '(') S[i] = ')';
		else if (S[i] == ')') S[i] = '(';
	}
	all_init();
	init();
	
	// パターン 3(パターン 2 の逆)
	long long ans3 = 0;
	for (int i = N; i >= 1; i -= 2) {
		for (int j = i; j <= N; j++) {
			if (2 * j - i > N) continue;
			ans3 += solve2(j, i);
			ans3 %= mod;
		}
	}

	// 出力
	cout << (ans1 + ans2 + ans3 + ans4) % mod << endl;
	return 0;
}

Compilation message

securitygate.cpp: In function 'int main()':
securitygate.cpp:216:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for (int i = 0; i < S.size(); i++) {
                  ~~^~~~~~~~~~
# Verdict Execution time Memory Grader output
1 Runtime error 648 ms 1048580 KB Execution killed with signal 9 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 648 ms 1048580 KB Execution killed with signal 9 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 648 ms 1048580 KB Execution killed with signal 9 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 648 ms 1048580 KB Execution killed with signal 9 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 648 ms 1048580 KB Execution killed with signal 9 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -