您的位置:首页 > 大数据 > 人工智能

2017 Multi-University Training Contest - Team 1 1006 Function(思维 循环节)

2017-07-25 19:38 495 查看
题意:给你一个序列a,是0到n-1的一个排列,给你一个序列b,是0到m-1的一个排列,问你有多少种不同的函数关系满足:f[i] = b[f[a[i]]] (0 < i < n).

官方题解:考虑置换 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
- 1l−1 个数的函数值也都确定下来了。

答案就是 \sum_{i
= 1}^{k} \sum_{j | l_i} {j \cdot cal_j}∑​i=1​k​​∑​j∣l​i​​​​j⋅cal​j​​ 改为 \prod_{i
= 1}^{k} \sum_{j | l_i} {j \cdot cal_j}∏​i=1​k​​∑​j∣l​i​​​​j⋅cal​j​​ ,其中 kk 是置换 aa 中循环节的个数, l_il​i​​ 表示置换 aa 中第 ii 个循环节的长度, cal_jcal​j​​ 表示置换 bb 中长度为 jj 的循环节的个数。

时间复杂度是 O(n + m) 。

官方的题解有些乱码。。。。可以参考帅神的博客:点击打开链接

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 1e6+5;
int a[maxn], b[maxn];
int n, m;
bool visA[maxn], visB[maxn];
int numA[maxn], numB[maxn];

int main(void)
{
int ca = 1;
while(cin >> n >> m)
{
memset(numA, 0, sizeof(numA));
memset(numB, 0, sizeof(numB));
memset(visA, 0, sizeof(visA));
memset(visB, 0, sizeof(visB));
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
for(int i = 0; i < m; i++)
scanf("%d", &b[i]);
int cntA = 0, cntB = 0;
for(int i = 0; i < n; i++)
{
int len = 0;
int tmp = i;
while(!visA[tmp])
{
len++;
visA[tmp] = 1;
tmp = a[tmp];
}
if(len)
numA[cntA++] = len;
}
for(int i = 0; i < m; i++)
{
int len = 0;
int tmp = i;
while(!visB[tmp])
{
len++;
visB[tmp] = 1;
tmp = b[tmp];
}
if(len) numB[len]++;
}
ll ans = 1;
for(int i = 0; i < cntA; i++)
{
ll tmp = 0;
for(int j = 1; j*j <= numA[i]; j++)
{
if(numA[i]%j == 0)
{
if(j*j == numA[i])
tmp += numB[j]*j;
else
tmp += numB[j]*j+numB[numA[i]/j]*numA[i]/j;
}
}
ans = ans*tmp%mod;
}
printf("Case #%d: %lld\n", ca++, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU 多校
相关文章推荐