zoukankan      html  css  js  c++  java
  • CF1089I Interval-Free Permutations

    CF1089I Interval-Free Permutations

    题目大意

    题目链接

    蔡老板是至高无上的世界首富,他手下有 (n) 名小弟(二五仔),编号为 (1dots n)。这些二五仔站成一排。从左到右,他们的编号构成了一个排列 (p_1, p_2, dots p_n)

    对于排列的一个子段 (p_l, p_{l+1}, dots, p_{r-1}, p_{r}),如果 (1 < r - l + 1 < n),且将这个子段排序后是连续的一段数值,则这个子段里的二五仔们会叛变。

    蔡老板要培养忠肝义胆的二五仔,因此不希望手下叛变。请你帮蔡老板数一数:有多少个长度为 (n) 的排列,满足没有子段会叛变呢?答案对一个质数 (P) 取模。

    本题一个测试点里有 (T) 组测试数据,但他们的模数 (P) 相同

    数据范围:(1leq Tleq 400)(10^8 leq Pleq 10^9)(1leq nleq 400)

    本题题解

    考虑用总数((n!))减去不合法的排列数。我们现在要研究不合法的排列长什么样。

    称【将子段排序后是连续的一段数值】是子段(也就是原题题面中的 interval)为不合法子段。那么合法的排列,就是不存在长度在 ([2, n - 1]) 中的不合法子段的排列。

    称一个不合法子段是极长的,当且仅当不存在另一个长度小于 (n) 的不合法子段包含它。发现,两个不合法子段如果有交,则它们的并也是不合法子段。因此,不合法的排列只有如下两种可能:

    • 由两段极长不合法子段组成,这两段不合法子段可能相交。形式化地,若这两个子段分别是 ([l_1, r_1], [l_2, r_2]),则 (l_1 = 1, r_2 = n),且 (r_1geq l_2 - 1)
    • 由三段及以上的极长不合法子段拼成,它们互不相交。形式化地,若这些子段分别是 ([l_1, r_2], [l_2, r_2], dots [l_k, r_k]),则 (l_1 = 1, r_k = n),且 (forall 1leq i < k: r_i + 1 = l_{i + 1})

    上述两种情况,不重不漏地刻画了所有不合法排列。因此只需要对这两种情况分别计数。

    设长度为 (i)合法排列数为 (f(i)),也就是答案。

    第一种不合法排列:发现两个子段中,必有一个包含的数值为 (1, 2, dots, i)(其中 (i) 是子段长度)。不妨假设它是左边的子段,然后把方案数乘以 (2) 即可。设 (h(i)) 表示有多少长度为 (i) 的排列,满足它的任何长度 (< i) 的前缀,不是【数值的一个前缀】。形式化地 (forall 1leq j < i: {p_k | k leq j} eq {1dots j})。求 (h(i)),可以继续使用【总数减不合法数量】的思想:(h(i) = i! - sum_{j = 1}^{i - 1}h(j)cdot (i - j)!)。求出 (h(i)) 后,第一种不合法的排列数量是 (2cdot sum_{i = 1}^{n - 1} h(i)cdot (n - i)!)。也就是枚举了左边子段的长度,后面的数可以任意排列:因为不管左边怎么样,后面任意排列,至少自己内部是一个不合法子段((i + 1dots n),连续的数值);当然,它可能还能向左延伸一点,也就是两个子段有交。

    第二种不合法排列:考虑设 (g(i, j)) 表示 (i) 个数,划分为 (j) 个不合法子段的方案数(不一定极长)。则:(g(i, j) = sum_{k = 1}^{i}g(i - k, j - 1)cdot k!),其中枚举的 (k) 是最后一个不合法子段的长度(这个子段内部可以任意排列,也就是 (k!) 种方案)。边界是 (g(0, 0) = 1)。注意,这里没有考虑子段的相对顺序,也就是最后一个子段里的数值,默认为 (i - k + 1dots i)。给此时的 (j) 个子段依次编号为 (1dots j)。现在要求 (j) 个子段都是极长的,那么相当于 (1dots j) 这些子段的子段,不能有连续数值,也就是:(sum_{j = 3}^{n - 1}g(n, j)cdot f(j))

    综上所述:

    [f(n) = n! - 2cdot sum_{i = 1}^{n - 1} h(i)cdot (n - i)! - sum_{j = 3}^{n - 1}g(n, j)cdot f(j) ]

    预处理答案,时间复杂度 (mathcal{O}(n^3))

    参考代码

    // problem: CF1089I
    #include <bits/stdc++.h>
    using namespace std;
    
    #define mk make_pair
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    
    template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
    template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }
    
    const int MAXN = 400;
    int MOD;
    
    inline int mod1(int x) { return x < MOD ? x : x - MOD; }
    inline int mod2(int x) { return x < 0 ? x + MOD : x; }
    inline void add(int &x, int y) { x = mod1(x + y); }
    inline void sub(int &x, int y) { x = mod2(x - y); }
    
    int fac[MAXN + 5];
    int h[MAXN + 5];
    int g[MAXN + 5][MAXN + 5];
    int f[MAXN + 5];
    
    void init(int n) {
    	
    	fac[0] = 1;
    	for (int i = 1; i <= n; ++i) {
    		fac[i] = (ll)fac[i - 1] * i % MOD;
    	}
    	
    	h[1] = 1;
    	for (int i = 2; i <= n; ++i) {
    		h[i] = fac[i];
    		for (int j = 1; j < i; ++j) {
    			sub(h[i], (ll)h[j] * fac[i - j] % MOD);
    		}
    	}
    	
    	g[0][0] = 1;
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= i; ++j) {
    			for (int k = 1; k <= i; ++k) {
    				add(g[i][j], (ll)g[i - k][j - 1] * fac[k] % MOD);
    			}
    		}
    	}
    	
    	f[1] = 1; f[2] = 2;
    	for (int i = 3; i <= n; ++i) {
    		f[i] = 0;
    		for (int j = 1; j < i; ++j) {
    			add(f[i], (ll)h[j] * fac[i - j] % MOD);
    		}
    		f[i] = mod1(f[i] * 2);
    		
    		for (int j = 3; j < i; ++j) {
    			add(f[i], (ll)g[i][j] * f[j] % MOD);
    		}
    		f[i] = mod2(fac[i] - f[i]); // 总 - 不合法
    	}
    }
    
    int main() {
    	int T;
    	cin >> T;
    	
    	cin >> MOD;
    	init(MAXN);
    	
    	while (T--) {
    		int n;
    		cin >> n;
    		cout << f[n] << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    2020年. NET Core面试题
    java Context namespace element 'component-scan' and its parser class ComponentScanBeanDefinitionParser are only available on JDK 1.5 and higher 解决方法
    vue 淡入淡出组件
    java http的get、post、post json参数的方法
    vue 父子组件通讯案例
    Vue 生产环境解决跨域问题
    npm run ERR! code ELIFECYCLE
    Android Studio 生成apk 出现 :error_prone_annotations.jar (com.google.errorprone:error) 错误
    记忆解析者芜青【总集】
    LwIP应用开发笔记之十:LwIP带操作系统基本移植
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/cf1089i.html
Copyright © 2011-2022 走看看