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 n−1 and a permutation b from 0 to m−1 .
Define that the domain of functionf 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 functionsf 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 from0 to n−1 mapped into different integers in these two functions.
The answer may be too large, so please output it in modulo109+7 .
Define that the domain of function
Please calculate the quantity of different functions
Two functions are different if and only if there exists at least one integer from
The answer may be too large, so please output it in modulo
Input
The input contains multiple test cases.
For each case:
The first line contains two numbersn, m . (1≤n≤100000,1≤m≤100000)
The second line containsn numbers, ranged from 0 to n−1 , the i -th number of which represents ai−1 .
The third line containsm 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
The second line contains
The third line contains
It is guaranteed that
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 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
考虑置换 a 的一个循环节,长度为 l ,那么有 $f(i) = b_{f(a_i)} = b_{b_{f(a_{a_i})}} = \underbrace{b_{\cdots b_{f(i)}}}_{l\text{ times }b}$ 。
那么 f(i) 的值在置换 b 中所在的循环节的长度必须为 l 的因数。
而如果 f(i) 的值确定下来了,这个循环节的另外 l−1 个数的函数值也都确定下来了。
答案就是 ∑i=1k∑j∣lij⋅calj 改为 ∏i=1k∑j∣lij⋅calj ,其中 k 是置换 a 中循环节的个数, li 表示置换 a 中第 i 个循环节的长度, calj 表示置换 b 中长度为 j 的循环节的个数。
时间复杂度是 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
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;
}
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;
}
阅读全文
0 0
- HDU 6038 Function
- HDU-6038 Function
- hdu 6038 Function(思维)
- HDU 6038 Function
- hdu 6038 Function
- HDU 6038 Function
- hdu 6038 Function
- HDU 6038 Function
- Function (HDU 6038)
- HDU 6038 Function【思维】
- hdu--6038--Function
- HDU 6038-Function
- hdu 6038 Function
- hdu 6038 Function
- Function HDU-6038
- HDU-6038 Function(思维)
- HDU 6038 Function (数学)
- HDU 6038 Function 置换群
- android常见问题解决方案
- 笨方法学Python 习题 23: 读代码
- POJ 1190 生日蛋糕(深搜+剪枝)
- c++实现单例模式
- resultType和resultMap总结
- hdu--6038--Function
- CSU-ACM2017暑期训练4-dfs D
- 将二叉搜索树转换成一个排序的双向链表
- poj1655—Balancing Act(树的重心)
- 集合框架的基础知识
- HTML5 本地数据库
- 【华为机试】找出字符串中第一个只出现一次的
- 常用工具类作业(还没学全 只是一部分)
- ubuntu-用xshell无密码连接虚拟机报错