hdu 6038 Function (思维题搞一搞)

时间:2022-02-20 17:07:13

f函数的限制关系形成多个环,b的排列也形成多个循环。f中每个环要合法赋值,环的大小要能被b的某个环的大小整除,方案为b环的大小

。再把f每个环的赋值方案相乘就是答案。例如f有环4,6,8。b环 2,3。ans= (2 )* (2 + 3)*(2)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
const ll md = 1e9 + 7;
const int MAXN = 1e5 + 10;
int fa1[MAXN], fa2[MAXN];
int sum1[MAXN], sum2[MAXN];
set<int>st1, st2;

int find1(int x)
{
return fa1[x] == x ? x : (fa1[x] = find1(fa1[x]));
}
void merge1(int x, int y)
{
x = find1(x);
y = find1(y);
if (x != y){
fa1[x] = y;
sum1[y] += sum1[x];
}
}

int find2(int x)
{
return fa2[x] == x ? x : (fa2[x] = find2(fa2[x]));
}
void merge2(int x, int y)
{
x = find2(x);
y = find2(y);
if (x != y){
fa2[x] = y;
sum2[y] += sum2[x];
}
}
int n, m;
int p[MAXN], q[MAXN];
int val[MAXN];
void init()
{
for (int i = 0; i < n; i++){
fa1[i] = i;
sum1[i] = 1;
}
for (int i = 0; i < m; i++){
fa2[i] = i;
sum2[i] = 1;
}
memset(val, 0, sizeof(val));
st1.clear();
st2.clear();
}
int main()
{
int cas = 1;
while (scanf("%d%d", &n, &m) != EOF){
init();
for (int i = 0; i < n; i++)
scanf("%d", &p[i]);
for (int i = 0; i < m; i++){
scanf("%d", &q[i]);
}
for (int i = 0; i < n; i++){
merge1(i, p[i]);
}
for (int i = 0; i < m; i++){
merge2(i, q[i]);
}
for (int i = 0; i < n; i++){
if (find1(i) == i){
st1.insert(i);
}
}
int MAX = 0;
for (int j = 0; j < m; j++){
if (find2(j) == j){
st2.insert(sum2[j]);
val[sum2[j]]++;
MAX = max(MAX, sum2[j]);
}
}
ll ans = 1;
ll tmp = 0;
set<int>::iterator it, it2;
for (it = st1.begin(); it != st1.end(); it++){
tmp = 0;
for (it2 = st2.begin(); it2 != st2.end(); it2++){
int big = *it2;
if (sum1[*it] % (*it2) == 0){
tmp += (*it2)*val[*it2];
tmp %= md;
}
/*for (int j = 1; j*j <= big; j++){
if (sum1[*it] % j == 0){
ans += (ll)j *val[*it];
ans %= md;
if (j*j == big)break;
}
}*/

}
ans = ans * tmp;
ans %= md;
}
printf("Case #%d: %lld\n", cas++, ans);
}
}