[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\n", ans);
	return 0;
}
/*input
10 5
5 1 4 3 2
output
26
*/

posted @ 2020-03-03 21:58  Chopsticks  阅读(128)  评论(0编辑  收藏  举报