zoukankan      html  css  js  c++  java
  • AT1879 2 つの山札

    题面

    题解

    直接求解比较麻烦,考虑将问题进行转化。

    设序列(a = {3, 1, 4, 2, 5}, b = {3, 2, 4, 1, 5}),那么我们构造一个正方形方格,将(a)放在横行,(b)放在竖行,可以画出下图。

    那么我们可以发现,方案数就是从左上走到右下的不同序列个数。

    这样我们可以( exttt{d} exttt{p}),设(f[i][j])表示走到((i, j))的方案数,那么显然(f[i][j] = f[i - 1][j] + f[i][j - 1])

    不过这样转移发现有重复。考虑到(a_i = b_j)(f[i][j])出现重复的必要条件,通过推导可以得出方程:(f[i][j] = f[i][j - 1] + f[i - 1][j] + [a_i = b_j]sum_{k geq 1}[a_{i - k} = b_{j - k}]f[i - k][j - k]mathrm{C}(t - 1)),其中(mathrm{C})表示卡特兰数,(t)表示(1)(k)之间有多少个(l)满足(a_{i - l} = b_{i - l})

    由于(a_i = b_j)只有(n)对,所以时间复杂度为(mathrm{O}(n ^ 2))

    代码

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if (ch == '-') w = -1, ch = getchar();
    	while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int N(2010), Mod(1e9 + 7);
    int n, m, fac[N], inv[N], A[N], B[N], f[N][N];
    inline int C(int n) { return 1ll * fac[n << 1] * inv[n] % Mod * inv[n + 1] % Mod; }
    int fastpow(int x, int y)
    {
    	int ans = 1;
    	for (; y; y >>= 1, x = 1ll * x * x % Mod)
    		if (y & 1) ans = 1ll * ans * x % Mod;
    	return ans;
    }
    
    int main()
    {
    	n = read(), m = n << 1, fac[0] = inv[0] = 1, f[1][1] = 1;
    	for (int i = 1; i <= m; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
    	inv[m] = fastpow(fac[m], Mod - 2);
    	for (int i = m - 1; i; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % Mod;
    	for (int i = 1; i <= n; i++) A[i] = read();
    	for (int i = 1; i <= n; i++) B[i] = read();
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    		{
    			if (i > 1 || j > 1) f[i][j] = (f[i - 1][j] + f[i][j - 1]) % Mod;
    			if (A[i] == B[j]) for (int k = 1, cnt = 0; k < i && k < j; k++)
    				if (A[i - k] == B[j - k])
    					f[i][j] = (f[i][j] - 1ll * C(cnt) *
    							f[i - k][j - k] % Mod + Mod) % Mod, ++cnt;
    		}
    	printf("%d
    ", f[n][n]);
    	return 0;
    }
    
  • 相关阅读:
    13.2 抽像类与体类(Abstract & Concrete Classes) 简单
    13.3 深度隔离的界面(Deeply Parted interface) 简单
    计算天数(C++)_学习 简单
    13.1.2 纯虚函数(Pure Virutal Functions) 简单
    C++ operator关键字(重载操作符) 简单
    二月一共多少天 简单
    重载运算符操作_学习 简单
    计算两个日期之间的天数(C++) 简单
    1.2 连接信号和响应函数 简单
    用Android手机做台式机无线网卡
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/11142101.html
Copyright © 2011-2022 走看看