hdu5399(计数)

本文探讨了给定一系列确定和不确定的函数映射后,如何计算能够形成自反映射的所有可能组合数量。通过先模拟确定函数并检查是否存在重复映射来排除不可能的情况,再利用排列组合的方法解决不确定函数部分。

题意:

有n个数字,并给出m个函数变化;

如果给出的函数变化是-1,代表这个函数不确定,可以任意写;

使

f1(f2(......fm(i))) = i;

成立的所有情况有几种;


思路:

现将确定的函数模拟一边;得到的值如果有重复映射,则0种可能,因为一旦又重复映射,我们就不能映射出1到n所有的值;

然后看不确定的函数个数;只需要留一个用来做调整,剩下的都是1到n的全排列;


#include <cstdio>
#include <cstring>

#define ll long long
const int N = 105;
const int MOD = 1e9 + 7;

int f[N][N], n, m, tmp[N];
ll A[N];

void change(int* F) {
	for (int i = 1; i <= n; i++)
		tmp[i] = F[tmp[i]];
}
bool judge(int k) {
	for (int i = 1; i <= n; i++)
		tmp[i] = i;
	for (int i = k - 1; i >= 0; i--)
		change(f[i]);
	int vis[N];
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= n; i++) {
		if(vis[tmp[i]])
			return false;
		vis[tmp[i]] = 1;
	}
	return true;
}
int main() {
	A[1] = 1;
	for (int i = 2; i <= N; i++) {
		A[i] = A[i - 1] * i % MOD;
	}
	while (scanf("%d%d", &n, &m) == 2) {
		memset(f, 0, sizeof(f));
		int k = 0, c = 0;
		for (int i = 1; i <= m; i++) {
			scanf("%d", &f[k][1]);
			if(f[k][1] == -1) {
				c++;
				continue;
			}
			for (int j = 2; j <= n; j++) {
				scanf("%d", &f[k][j]);
			}
			k++;
		}
		bool ok = judge(k);
		if (!ok) {
			printf("0\n");
			continue;
		}
		if (c == 0) {
			int flag = 0;
			for (int i = 1; i <= n; i++)
				if (tmp[i] != i) {
					flag = 1;
					break;
				}
			if (flag) {
				printf("0\n");
				continue;
			}
		}
		ll ans = 1;
		for (int i = 1; i < c; i++) {
			ans = ans * A[n] % MOD;
		}
		printf("%lld\n", ans); 
	}
}



f1(f2(fm(i)))=i







f
1
(f2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值