hdu 6038 Function (思维题搞一搞)

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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值