Function
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1453 Accepted Submission(s): 680
Problem Description
You are given a permutation
a
from
0
to
n−1
and a permutation
b
from
0
to
m−1
.
Define that the domain of function f is the set of integers from 0 to n−1 , and the range of it is the set of integers from 0 to m−1 .
Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n−1 .
Two functions are different if and only if there exists at least one integer from 0 to n−1 mapped into different integers in these two functions.
The answer may be too large, so please output it in modulo 109+7 .
Define that the domain of function f is the set of integers from 0 to n−1 , and the range of it is the set of integers from 0 to m−1 .
Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n−1 .
Two functions are different if and only if there exists at least one integer from 0 to n−1 mapped into different integers in these two functions.
The answer may be too large, so please output it in modulo 109+7 .
Input
The input contains multiple test cases.
For each case:
The first line contains two numbers n, m . (1≤n≤100000,1≤m≤100000)
The second line contains n numbers, ranged from 0 to n−1 , the i -th number of which represents ai−1 .
The third line contains m numbers, ranged from 0 to m−1 , the i -th number of which represents bi−1 .
It is guaranteed that ∑n≤106, ∑m≤106 .
For each case:
The first line contains two numbers n, m . (1≤n≤100000,1≤m≤100000)
The second line contains n numbers, ranged from 0 to n−1 , the i -th number of which represents ai−1 .
The third line contains m numbers, ranged from 0 to m−1 , the i -th number of which represents bi−1 .
It is guaranteed that ∑n≤106, ∑m≤106 .
Output
For each test case, output "
Case #
x
:
y
" in one line (without quotes), where
x
indicates the case number starting from
1
and
y
denotes the answer of corresponding case.
Sample Input
3 2 1 0 2 0 1 3 4 2 0 1 0 2 3 1
Sample Output
Case #1: 4 Case #2: 4
Source
//题意:题目自己先看一边,不好解释,我讲组样例:
3 2
1 0 2
0 1
第一行的3表示a数组有3个元素,2表示b数组有2个元素,接下来两行分别是a、b数组。
根据题意可列方程:
F(0)=b(F(1))
F(1)=b(F(0))
F(2)=b(F(2))
打表:
F(0) F(1) F(2)
0 0 0
0 0 1
1 1 0
1 1 1
共有这么4种情况,输出4 。
这么讲应该懂了吧QAQ
//思路:
F(0)=b(F(1))
F(1)=b(F(0))
F(2)=b(F(2))
从这里应该可以看出F(0)的值与F(1)是有关的,F(2)的值与它自己有关的,我们可以根据这个建个图:
0->1,1->0,2->2(a图)
还可以看出,b的值与它的下标也有关系,根据这个也再建个图:
0->0,1->1(b图)
我们分别计算出a、b里环的个数和每个环里元素的个数,设b中一个环是X,a中一个环是Y,若X里的元素个数等于Y或是Y的因子(即能被整除),那么a里这个环的情况数+=X的元素个数(因为Y中的一个顶点都可以是X里元素的一种,Y里知道一个顶点的值能推出Y里其他点的值)。那么总数sum=a里每个环的情况数的乘积。
这里算a里环的情况数的时候采用枚举,a里环一个个枚举,每个环去算的时候把b里的环都枚举判断一遍,非常暴力,竟然没TLE,神奇...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
const int MAX = 100000 + 100;
const int mod = 1000000007;
long long sum;
int n, m;
int a[MAX], b[MAX];
int vis[MAX];//图里的点是否被访问过
int amap[MAX];//a图
int ans;//a图里环的个数
int lena[MAX];//a里每个环里的点的个数
int bmap[MAX];//b图
int cnt;//b图里环的个数
int lenb[MAX];//b里每个环里的点的个数
//计算图里环的个数和每个环里点的个数
//标准的可以去看下tarjan算法,我这个是自己瞎写的,复杂度比较高...
int cul(int *map, int *len, int nn)
{
int i, num;
int lenth = 1;
queue<int>q;
memset(vis, 0, sizeof(vis));
num = 0;
q.push(0);
vis[0] = 1;
while (true)
{
while (!q.empty())
{
int now = q.front();
q.pop();
int next = map[now];
if (!vis[next])
{
vis[next] = 1;
q.push(next);
lenth++;
}
}
len[num] = lenth;
num++;
for (i = 0; i < nn; i++)
{
if (vis[i] == 0)
{
q.push(i);
vis[i] = 1;
lenth = 1;
break;
}
}
if (i == nn)
break;
}
return num;
}
int main()
{
int Case = 1;
while (scanf("%d%d", &n, &m) != EOF)
{
memset(amap, 0, sizeof(amap));
memset(bmap, 0, sizeof(bmap));
//输入并建a图
for (int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
amap[i] = a[i];
}
//输入并建b图
for (int i = 0; i < m; i++)
{
scanf("%d", &b[i]);
bmap[i] = b[i];
}
printf("Case #%d: ", Case++);
//分别计算a、b图里环的个数和每个环里点的个数
ans = cul(amap, lena, n);
cnt = cul(bmap, lenb, m);
sum = 1;
long long kk;
for (int i = 0; i < ans; i++)
{
kk = 0;
//计算每个环可能的情况数
for (int j = 0; j < cnt; j++)
{
if (lena[i] % lenb[j] == 0)
{
kk = (kk+ lenb[j]) % mod;
}
}
//计算总情况数
sum *= kk;
sum = sum%mod;
}
sum = sum % mod;
printf("%lld\n", sum);
}
return 0;
}