• [ABC217]F


    [ABC217]F - Make Pair

    题目

    (2N)个学生,编号(1,2,3ldots 2N),其中有(M)对学生关系友好,教师每次可以从中选出一对相邻的学生,且他们关系友好,然后将这对学生删除(注意删除后学生的相邻关系改变).

    求出删除所有学生的方案数,取模.

    思路

    这种问方案数,还取模的题基本都是DP.看下数据范围大概在(O(n^3))左右.

    应该不难想到区间DP.

    (f_{i,j})表示消掉(isim j)所有学生的方案数.考虑如何从小区间推到大区间,我们把第(i)个人单独拿出来,枚举(kin [i+1, j]),如果第(i)个人和第(k)个人关系友好,我们可以先合并(i+1sim k-1)的人,然后合并(i,k)(k+1sim j)(后面这两个顺序是可以换的).为了方便,令(n_1=k-i+1),(n_2=j-k)(两边的人数),产生的贡献就是

    [f_{i,k}cdot f_{k+1,j}cdot C^{n_2}_{n_1+n_2} ]

    这是一个经典的组合数问题.

    我们称(isim k)为左半边,(k+1sim j)为右半边.

    设合并左半边的操作序列为(A_1,A_2,ldots ,A_{n_1}),合并右半边的操作序列为(B_1,B_2,ldots ,B_{n_2}),显然,合并(isim j)(A,B)原来的操作顺序不能改变,即对于所有的(iin [2,n_1]),(A_{i-1})要在(A_i)之前出现,对于(B)也同理.

    原问题等价于从(n_1+n_2)个小球中选出(n_1)个球的方案数,这样理解:所有小球等价于合并全区间的操作序列, 选出的小球代表左半边的操作序列,剩下的代表右半边的操作序列,比如,6个小球中,选出第(1,2,4,6)个,对应的合并后的操作序列就是(A_1,A_2,B_1,A_3,B_2,A_4).

    因此,合并(isim j)所有人的操作方案数就是(C^{n_2}_{n_1+n_2}).

    最后,答案显然就是(f_{1,2n}).

    代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    typedef long long lint;
    const int N = 410;
    const lint mod = 998244353;
    int n , m;
    int rel[N][N];
    lint f[N][N];
    
    lint fac[N];
    lint inv[N];
    
    lint pow_(lint a , int p) {
    	lint res = 1;
    	while(p) {
    		if(p & 1)
    			res = res * a % mod;
    		a = a * a % mod;
    		p >>= 1;
    	}
    	return res;
    }
    signed main() {
    	cin >> n >> m;
    	n *= 2;
    	for(int i = 1 ; i <= m ; i++) {
    		int u , v;
    		cin >> u >> v;
    		rel[u][v] = rel[v][u] = 1;
    		if(u == v + 1 || v == u + 1)
    			f[u][v] = f[v][u] = 1;
    	}
    
    	fac[0] = 1;
    	for(int i = 1 ; i <= n ; i++)
    		fac[i] = fac[i - 1] * i % mod;
    	for(int i = 1 ; i <= n ; i++)
    		inv[i] = pow_(fac[i] , mod - 2);
    
    	for(int i = n ; i > 0 ; i--)
    		for(int j = i + 3 ; j <= n ; j+=2) {
    			if(j - i + 1 & 1)
    				continue;
    			if(rel[i][j])
    				f[i][j] += f[i + 1][j - 1];
    			for(int k = i + 1 ; k < j ; k += 2)
    				if(rel[i][k])
    					f[i][j] += f[i + 1][k - 1] * f[k + 1][j] % mod
    					           * fac[j - i + 1 >> 1] % mod
    					           * inv[j - k >> 1] % mod
    					           * inv[j - i + 1 - (j - k) >> 1] % mod ,
    					f[i][j] %= mod;
    		}
    	cout << f[1][n];
    	return 0;
    }
    
  • 相关阅读:
    WPF treeview 多层次绑定问题 HierarchicalDataTemplate 和 CompositeCollection
    Difference between Visibility.Collapsed and Visibility.Hidden
    WPF style的继承
    Asp.net个性化服务《系列03_购物车》
    SQLServer2005中的uniqueidentifier数据类型与NEWID()函数
    扉页语
    Asp.net个性化服务《系列01_概述》
    Asp.net个性化服务《系列02_快速的匿名用户个性化》
    2010年java课程体系
    easyui修改提示窗
  • 原文地址:https://www.cnblogs.com/dream1024/p/15244203.html
Copyright © 2020-2023  润新知