zoukankan      html  css  js  c++  java
  • floj2963

    题目链接

    题意:

    现在有n(n<=300)个左括号,要求合理安排n个右括号使其成为一个合法括号序列
    但是现在有m(m<=45000)个要求,对于每个要求:
    从左往右数第(a_i)个左括号所对应的右括号在第(b_i)个左括号所对应的右括号的前面
    最后询问一共有多少种方案数(结果对998244353取模)

    题解:

    求方案数,基本锁定是dp
    考虑区间dp~~(这个我也不知道是怎么想到的难道是n^3的复杂度??)~
    定义(dp_{l,r})表示合法的括号区间[l,r](l,r指左括号的编号)
    考虑用第一对括号(即l)进行转移(设剩下的合法括号串为preans)

    • ()preans (dp_{l,r}=dp_{l,r}+dp_{l+1,r};) 条件:[l+1,r]没有限制其对应右括号在l的右括号前面
    • (preans) 转移同上; 条件:l没有限制其对应右括号在[l+1,r]的右括号前面
    • (pre)ans/(prea)ns/....(即从中间截断)
      枚举断点为k:(dp_{l,r}=dp_{l,r}+dp_{l+1,k}*dp_{k+1,r};)
      条件:l没有限制其对应右括号在[l+1,k]的右括号的前面并且[k+1,r]没有限制其对应右括号在[l,k]的右括号前面

    现在我们关心如何快速判断是否符合条件
    对于限制条件的数对((a_i,b_i))(含义如题)
    我们记录(mp[a_i][b_i]=1)
    然后再用sum[][]对mp[][]做一个二维前缀和
    对于一个矩形区域(x,y) (z,w),如果此区域所有数之和为0
    则表示不存在[x,z]限制其对应右括号在[y,w]的右括号前面这样的条件

    注意:

    可能存在自环。这样要输出0.

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=305,mod=998244353;
    int t,n,m;
    int f[N][N],mp[N][N],sum[N][N];
    bool vis[N][N];
    inline int s(int a1,int b1,int a2,int b2)
    {
    	return sum[a2][b2]-sum[a1-1][b2]-sum[a2][b1-1]+sum[a1-1][b1-1];
    }
    int dp(int l,int r)
    {
    	int &d=f[l][r];
    	if(vis[l][r])return d;
    	vis[l][r]=true;
    	if(l==r)return d=1;
    	d=0;
    	if(!s(l+1,l,r,l))d=(d+dp(l+1,r))%mod;
    	if(!s(l,l+1,l,r))d=(d+dp(l+1,r))%mod;
    	for(int k=l+1;k<r;++k)
    		if(!s(l,l+1,l,k) && !s(k+1,l,r,k))
    			d=(d+1ll*dp(l+1,k)*dp(k+1,r)%mod)%mod;
    	return d%mod;
    }
    int main()
    {
    	scanf("%d",&t);
    	while(t--)
    	{
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;++i)
    			fill(vis[i]+1,vis[i]+n+1,0),
    			fill(mp[i]+1,mp[i]+n+1,0),
    			fill(sum[i]+1,sum[i]+n+1,0);
    		bool flag=0;
    		for(int i=1;i<=m;++i)
    		{
    			int u,v;scanf("%d%d",&u,&v);
    			mp[u][v]=1;
    			if(u==v)flag=1;
    		}
    		if(flag){puts("0");continue;}
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+mp[i][j];
    		printf("%d
    ",dp(1,n));
    	}
    	return 0;
    }
    
  • 相关阅读:
    云原生技术实践,起步k8s
    线程,同步构造
    线程,限制的异步操作
    DotNet Core管道通信
    打下设计模式
    739--Daily Temperatures
    1021--RemoveOutermostParentheses
    Java并行程序基础。
    155--MinStack
    1047--Remove All Adjacent Duplicates In String
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13623998.html
Copyright © 2011-2022 走看看