【区间dp】括号序列再战猪猪侠

ydc的题解是只需要两维状态 = =

可是。。。可是我必须写三维才能AC TAT

all表示区间[L, R]是(A) 还是 AB。。

为了O(1)判断处理一个二维数组的前缀和。。

还有这个鬼要特判 u == v的情况

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

int read()
{
	int n = 0, sign = 1; char c = getchar();
	while(c < '0' || c > '9') {if(c == '-') sign = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
	return n * sign;
}

const int Mod = 998244353;
const int Nmax = 305;

int N, M;
struct Square{
	int sum[Nmax][Nmax];
	
	inline void make_sum()
	{
		for (int i = 1; i <= N; ++i)
		for (int j = 1; j <= N; ++j)
			sum[i][j] += sum[i - 1][j];
		for (int i = 1; i <= N; ++i)
		for (int j = 1; j <= N; ++j)
			sum[i][j] += sum[i][j - 1];
	}
	
	inline int get_sum(int x1, int x2, int y1, int y2)
	{
		int temp = sum[x2][y2] + sum[x1 - 1][y1 - 1];
		temp -= sum[x1 - 1][y2] + sum[x2][y1 - 1];
		return temp;
	}
}s;

int dp[Nmax][Nmax][2];
inline void Add(int &a, int b)
{
	a += b;
	while (a > Mod) a -= Mod;
}

int dfs(int L, int R, bool all)
{
	if(L == R) return all;
	if(~dp[L][R][all]) return dp[L][R][all];
	
	int &ans = dp[L][R][all] = 0;
	if (all) {
		if(!s.get_sum(L + 1, R, L, L)) Add(ans, dfs(L + 1, R, 0) + dfs(L + 1, R, 1));
	} else for (int k = L; k < R; ++k) {
		if(!s.get_sum(L + 1, k, L, L) && !s.get_sum(L, L, k + 1, R) && !s.get_sum(L + 1, k, k + 1, R)) 
		{
			//printf("%d %d %d\n", L, k, R);
			Add(ans, (long long)dfs(L, k, 1) * ( (long long)dfs(k + 1, R, 0) + dfs(k + 1, R, 1) ) % Mod);
		}
	}
	//printf("dp[%d][%d][%d] = %d\n", L, R, all, ans);
	return ans;
}

int main()
{
	freopen("brackets.in", "r", stdin);
	freopen("brackets.out", "w", stdout);
	
	for (int T = read(); T --; )
	{
		N = read(), M = read();
		memset(s.sum, 0, sizeof(s.sum));
		bool flag = 0;
		while (M --)
		{
			int u = read(), v = read();
			s.sum[v][u] = 1; 
			if (u == v) flag = 1; 
		}
		s.make_sum();
		
		memset(dp, -1, sizeof(dp));
		printf("%d\n", flag ? 0 : (dfs(1, N, 0) + dfs(1, N, 1)) % Mod);
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值