題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5399
題意:給你m個映射,每個自變量x,對應一個f(x),這m個映射中有某一些已知的,給出你從1到n對應的映射值,剩下的一些不知道映射關係的,給你-1,要求找出符合條件的映射組合有多少組,其中要求是:對於i從1到n都滿足f1(f2(……fm(i)))=i
思路:開個腦洞發現:如果-1的個數不止一個,那麼只有最後一個-1所對應的映射是確定的,其他的都是任意的,如果-1的個數,只有一個,那麼結果就是1,如果沒有-1,那麼還需要判斷本身這個映射是不是滿足條件。在做這些之前還需要考慮,這個映射是不是一一對應的,也就是這個映射是不是一個函數,只有這樣才能繼續討論-1個數的問題,如果不是一一對應的,那麼不同的i對應同樣的f(i)就回不到i。
官方解釋來一個幫助理解:首先要求每個f(i)是個排列,否則如果某個f(i)將兩個數映射向同一個數,那麼最後這兩個數得到的值一定相同。如果還剩一個位置爲-1,那麼這個排列是唯一確定的,假設,那麼所以假設有c(c≥1)個-1,那麼答案爲(n!)^{c-1} 個可行的方案。
注意特判所有函數都已知的情況。
代碼:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-8)
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 100005;
int n, m;
int b[105][105];
const ll mod = 1e9 + 7;
ll a[105];
int check()
{
int a[105];
int f[105];
for(int i=1;i<=n;i++)
a[i]=i;
for(int i=m; i>=1; i--)
{
for(int j=1; j<=n; j++)
f[j]=b[i][a[j]];
for(int j=1; j<=n; j++)
a[j]=f[j];
}
for(int i=1;i<=n;i++)
if(a[i]!=i)
return 0;
return 1;
}
int main () {
a[0] = 1;
for (int i = 1; i <= 100; i++)
a[i] = i * a[i - 1] % mod;
while(scanf("%d%d", &n, &m)!=EOF)
{
int k = 0;
int flag = 0;
for (int i = 1; i <= m; i++)
{
int sum[111] = {0};
scanf("%d", &b[i][1]);
if (b[i][1] == -1) {
k++;
continue;
}
sum[b[i][1]]++;
for (int j = 2; j <= n; j++)
{
scanf("%d", &b[i][j]);
sum[b[i][j]]++;
if (sum[b[i][j]] > 1) flag = 1;
}
}
if (flag) {
printf("0\n");
continue;
}
if (k == 0) {
printf("%d\n", check());
continue;
}
ll ans = 1;
k--;
while(k--) {
ans = ans * a[n];
ans %= mod;
}
printf("%I64d\n", ans);
}
return 0;
}