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=1k∑j∣lij⋅calj 改为 \prod_{i
= 1}^{k} \sum_{j | l_i} {j \cdot cal_j}∏i=1k∑j∣lij⋅calj ,其中 kk 是置换 aa 中循环节的个数, l_ili 表示置换 aa 中第 ii 个循环节的长度, cal_jcalj 表示置换 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;
}
官方题解:考虑置换 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=1k∑j∣lij⋅calj 改为 \prod_{i
= 1}^{k} \sum_{j | l_i} {j \cdot cal_j}∏i=1k∑j∣lij⋅calj ,其中 kk 是置换 aa 中循环节的个数, l_ili 表示置换 aa 中第 ii 个循环节的长度, cal_jcalj 表示置换 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;
}
相关文章推荐
- 2017 Multi-University Training Contest - Team 1 1006 Function
- 2017 Multi-University Training Contest - Team 1 1006 Function
- 2017 Multi-University Training Contest - Team 1 1006&&HDU 6038 Function【DFS+数论】
- 2017 Multi-University Training Contest - Team 1 1006 【思维+强联通找环】
- 2017 Multi-University Training Contest - Team 2 :1006 Funny Function(找规律+逆元+快速幂取模)
- 2017 Multi-University Training Contest - Team 1--1006 Function
- 2017 Multi-University Training Contest - Team 1 1006 Function(置换群)
- HDU 6038 Function(找规律)——2017 Multi-University Training Contest - Team 1
- 2017 Multi-University Training Contest - Team 2 - 1006
- HDU-6060 RXD and dividing - 2017 Multi-University Training Contest - Team 3(思维+最小斯坦纳树)
- 2017 Multi-University Training Contest - Team 3 1005 RXD and dividing 【思维 + 贪心】
- 2017 Multi-University Training Contest - Team 1 :Function
- 2017 Multi-University Training Contest - Team 2,HDU 6045 Is Derek lying?(思维水题)
- 2017 Multi-University Training Contest - Team 5 1008 【思维 + 01背包思想】
- HDU-6105 Gameia - 2017 Multi-University Training Contest - Team 6(思维之找规律或二分图最大匹配)
- hdoj 6050(2017 Multi-University Training Contest - Team 2) Funny Function
- 2017 Multi-University Training Contest - Team 2 1006
- HDU 6127 Hard challenge(思维+计算几何)——2017 Multi-University Training Contest - Team 7
- hdu 6045 简单的思维题 2017 Multi-University Training Contest - Team 2
- HDU 6055 Regular polygon(计算几何+思维)——2017 Multi-University Training Contest - Team 2