您的位置:首页 > 其它

2017年多校赛第一场 1006 Function(枚举)

2017-07-26 10:20 453 查看
这道题所有情况满足的情况下会构成一个环,我们很容易想到枚举环中的一个点,环中的其他点就都可以得出了。

这道题是问一共有多少种所有情况都满足的情况。所以我们先预处理a里面的循环节,统计一下长度为i的循环节有几个。然后预处理b里面的循环节,同样统计长度为i的循环节有几个。

最后枚举一下,假设a数组中有循环节长度为i,那么在b中枚举循环节为i的因子的。比如j为i的因子,那么此时就会多出j * num_b[j]种情况。枚举完之后,得到a数组中循环节为i时有tmp种情况。那么再看a中有多少个循环节长度为i。假设有两个,也就是a中有两个环同时都有tmp种情况,那么总的情况数就是tmp^2种,答案ans * tmp^2即可。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <cctype>
#include <ctime>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)
#define eps 1e-9

typedef long long ll;
typedef pair<int, int> pii;

const int INF = 0x7fffffff;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;
bool vst[maxn];
int n, m;
int a[maxn], b[maxn];
int nx[maxn];
ll num_a[maxn], num_b[maxn];

int main() {
int Case = 1;
while(cin >> n >> m) {

for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
for(int i = 0; i < m; i++)
scanf("%d", &b[i]);
for(int i = 0; i < n; i++) {
nx[a[i]] = i;
}

memset(vst, 0, sizeof(bool) * maxn);
memset(num_a, 0, sizeof(num_a));
memset(num_b, 0, sizeof(num_b));

for(int i = 0; i < n; i++) {
if(!vst[i]) {
int now = nx[i];
int cnt = 1;
vst[now] = 1;
while(now != i){
now = nx[now];
vst[now] = 1;
cnt++;
}
num_a[cnt]++;
}
}

memset(vst, 0, sizeof(vst));

for(int i = 0; i < m; i++) {
if(!vst[i]) {
int now = b[i];
int cnt = 1;
vst[now] = 1;
while(now != i){
now = b[now];
cnt++;
vst[now] = 1;
}
num_b[cnt]++;
}
}

ll ans = 1;
for(int i = 1; i <= n; i++) {
if(num_a[i]) {
int Max = sqrt(i + 0.5);
ll tmp = 0;
for(int j = 1; j <= Max; j++) {
if(i % j == 0) {
tmp += (j * num_b[j]) % mod;
if(j * j != i)
tmp += ((i / j) * num_b[i / j]) % mod;
}
}
for(int j = 0; j < num_a[i]; j++)
ans = ans * tmp % mod;
}
}
printf("Case #%d: %I64d\n", Case++, (ans % mod));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: