hdu--6038--Function

来源:互联网 发布:知乎 永不瞑目 编辑:程序博客网 时间:2024/05/30 23:16

Function

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1502    Accepted Submission(s): 707


Problem Description
You are given a permutation a from 0 to n1 and a permutation b from 0 to m1.

Define that the domain of function f is the set of integers from 0 to n1, and the range of it is the set of integers from 0 to m1.

Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n1.

Two functions are different if and only if there exists at least one integer from 0 to n1 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(1n100000,1m100000)

The second line contains n numbers, ranged from 0 to n1, the i-th number of which represents ai1.

The third line contains m numbers, ranged from 0 to m1, the i-th number of which represents bi1.

It is guaranteed that n106, m106.
 

Output
For each test case, output "Case #xy" 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 21 0 20 13 42 0 10 2 3 1
 

Sample Output
Case #1: 4Case #2: 4
 

Source
2017 Multi-University Training Contest - Team 1

官方题解:

考虑置换 aa 的一个循环节,长度为 ll ,那么有 $f(i) = b_{f(a_i)} = b_{b_{f(a_{a_i})}} = \underbrace{b_{\cdots b_{f(i)}}}_{l\text{ times }b}$ 。

那么 f(i)f(i) 的值在置换 bb 中所在的循环节的长度必须为 ll 的因数。

而如果 f(i)f(i) 的值确定下来了,这个循环节的另外 l - 1l1 个数的函数值也都确定下来了。

答案就是 \sum_{i = 1}^{k} \sum_{j | l_i} {j \cdot cal_j}i=1kjlijcalj 改为 \prod_{i = 1}^{k} \sum_{j | l_i} {j \cdot cal_j}i=1kjlijcalj ,其中 kk 是置换 aa 中循环节的个数, l_ili 表示置换 aa 中第 ii 个循环节的长度, cal_jcalj 表示置换 bb 中长度为 jj 的循环节的个数。

时间复杂度是 \mathcal{O}(n + m)O(n+m) 。

我的思路:

这题主要的是去找循环节,

分析样例:3 4

2 0 1

0 2 3 1

可以推出:a序列有个长度为3的循环节,即a[0]=2,a[1]=0,a[2]=1。

       b序列有长度为1和3的循环节  长度为1的:b[0]=0;长度为3的:b[1]=2,b[2]=3,b[3]=1;

求解:

1,要满足f(i)=b[f(a[i])];枚举数列a中的循环x,然后同理再找出b中循环y,但需要满足y的长度是x的因子

2,由于循环可以旋转,则每一个长度为len(y)的循环y贡献的方法个数为tol(y)=num(y)*len(y)  (分别表

     示y循环的长度和个数),将该x的每一个tol(y)进行累加,tol(x)=tol(y1)+tol(y2)+....+tol(yn);yi都是

     x的因子。

3,由于不同x之间相互独立,ans=tol(x1)*tol(x2)*.....*tol(xn);

代码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<bits/stdc++.h>
using namespace  std;
typedef long long ll;
const int N=1e5+10;
const ll mod=1e9+7;
int a[N],b[N];
int aa[N],bb[N];
int vis[N];
int main()
{
    int k=1;
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        for(int i=0; i<m; i++)
            scanf("%d",&b[i]);
        memset(vis,0,sizeof(vis));
        memset(aa,0,sizeof(aa));
        memset(bb,0,sizeof(bb));
        for(int i=0; i<n; i++)
        {
            int cnt=0;
            int x=i;
            while(!vis[x])
            {
                cnt++;
                vis[x]=1;
                x=a[x];
            }
            aa[cnt]++;///a该循环节的个数++
        }
        memset(vis,0,sizeof(vis));
        for(int i=0; i<m; i++)
        {
            int cnt=0;
            int x=i;
            while(!vis[x])
            {
                cnt++;
                vis[x]=1;
                x=b[x];
            }
            bb[cnt]++;///b该循环节的个数++
        }
        ll sum=1;
        for(int i=1; i<=n; i++)
        {
            if(aa[i])
            {
                ll ans=0;
                for(int j=1; j<=i; j++) ///在b的循环节中找到和a匹配的,即a的因子
                    if(i%j==0)
                        ans=(ans+bb[j]*j)%mod;///循环节的个数*循环节的长度,代表循环节里的这些数都可以形成f
                while(aa[i]--) ///对于a每个循环节都有ans个,所以*
                    sum=sum*(ans)%mod;
            }
        }
        printf("Case #%d: ",k++);
        printf("%I64d\n",sum);
    }
    return 0;
}

原创粉丝点击