• [Test1.11]-T3对合


    Description:

    一个排列 (A_n) 被称为是对合的,当且仅当:
    ∀1 ≤ i ≤ n, (A_{Ai} = i)
    Cob 想知道长度为 (n) 的排列中,有多少个具有对合的性质。但他不幸
    发现,这是个水题。因此,他把问题加强了一下,抛给了你:
    给定一个 (1)~(k) 的排列 (B_k) (k ≤ n),试求出:有多少个长度为 (n) 的对合
    排列,满足 (B_k) 是其子序列。
    由于答案可能很大,请对 1004535809 (479 × 221 + 1) 取模后输出。

    Input:

    第一行两个整数 (n), (k)
    第二行 (k) 个整数,表示 (B_k)

    Output:

    一行一个整数,表示答案

    数据范围:

    1 ≤ k ≤ n ≤ 1e4

    Solution:

    首先找题目性质:
    发现枚举(B_i)的前(m)个数在(1)~(k)匹配时
    剩下(k-m)个数在k之外按顺序排好之后会一个找一个人回到原来的(1)~(k)匹配
    那么前m个数需要按照顺序一个一个插入,所以方案是唯一的
    那么后面的(k-m)个数可以通过组合数算方案数,剩下还有(n)-(k)个数可以发现就是没有任何限制的对合排列
    直接递推预处理即可

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define R register
    #define ll long long
    using namespace std;
    namespace IO
    {
    	template<class T>
    	void rea(T &x)
    	{
    		char ch=getchar();int f(0);x = 0;
    		while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
    		while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    		x = f?-x:x;
    	}
    	template<class T>
    	T max(T a, T b) {return (a>b?a:b);}
    	template<class T>
    	T min(T a, T b) {return (a<b?a:b);}
    }
    using IO::rea;
    #define mod 1004535809
    long long n, k, b[10005], JieCheng[10005], inv[10005], ans, f[10005];
    long long C(long long n, long long k){if(k > n) return 0;return JieCheng[n]*inv[k]%mod*inv[n-k]%mod;}
    int kb[10005], is[10005];
    bool vis[10005];
    bool check(int m)
    {
    	memset(vis, 0, sizeof vis);
    	for(R int i = 1; i <= m; ++i) kb[i] = b[i];
    	sort(kb+1, kb+1+m);
    	for(R int i = 1; i <= m; ++i) is[kb[i]] = i;
    	for(R int i = 1; i <= m; ++i) if(!vis[kb[i]])
    	{
    		int FG = i, lunhuan = 0;
    		vis[kb[i]] = 1;
    		while(!vis[b[FG]]) vis[b[FG]] = 1, FG = is[b[FG]], lunhuan++;
    		if(lunhuan >= 2) return 0;
    	}
    	return 1;
    }
    int main()
    {
    	freopen("permu.in","r",stdin);
    	freopen("permu.out","w",stdout);
    	using IO::max;using IO::min;
    	rea(n), rea(k);
    	for(R int i = 1; i <= k; ++i) rea(b[i]);
    	JieCheng[1] = inv[1] = JieCheng[0] = inv[0] = 1;
    	f[1] = f[0] = 1;
    	for(R int i = 2; i <= max(n, k); ++i) JieCheng[i] = JieCheng[i-1]*i%mod;
    	for(R int i = 2; i <= max(n, k); ++i) inv[i] = inv[mod%i]*(mod-mod/i)%mod;
    	for(R int i = 2; i <= max(n, k); ++i) inv[i] = inv[i-1]*inv[i]%mod;
    	for(R int i = 2; i <= max(n, k); ++i) f[i] = (f[i-1]+(i-1)*f[i-2])%mod;
    	for(R int i = 0; i <= k; ++i)
    	{
    		long long X = 0, Y;
    		if(check(i)) X = 1;
    		Y = C(n-k, k-i);
    		ans = (ans+X*Y*f[n-2*k+i])%mod;
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    /*input
    10 5
    5 1 4 3 2
    output
    26
    */
    
    
  • 相关阅读:
    Codeforces Round #652 (Div. 2)
    Codeforces Round #651 (Div. 2)
    The 2017 China Collegiate Programming Contest, Qinhuangdao Site
    2017中国大学生程序设计竞赛-哈尔滨站
    Codeforces Global Round 8
    [CF768D] Jon and Orbs
    2020牛客暑期多校训练营(第一场)I
    2020牛客暑期多校训练营(第一场)F
    [HDU5769] Substring
    [PA2010] Riddle
  • 原文地址:https://www.cnblogs.com/heanda/p/12404929.html
Copyright © 2020-2023  润新知