(2017多校训练第一场)HDU - 6038 Function 排列分解

本文探讨了如何利用抽象代数中的循环排列概念解决特定函数解的问题。通过将排列分解为若干循环排列,并借助编程手段搜索所有可能的解,得出最终答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果不知道抽象代数(近世代数)中的排列分解这个知识点,建议去学习一下再来看这道题目。

直接看第二个样例吧,按照题目的意思可以得到如下方程。


然后进一步可得


函数有多少种,其实也就是上面这个方程有多少组解。

现在来观察一下这个方程,多么漂亮的形式,是不是很类似抽象代数中的循环排列呢?


不就说明了x是一个3阶循环排列中的元素吗!

不信的话,来看下面这个3阶循环排列


我们把f(0) = 2或者f(0) = 3或者f(0) = 1带入第一个方程发现都是成立的,同理第二和第三个方程也是这样,带入2 3 1也都是成立的。

但是实际上3个方程之间会相互制约,答案并不是9种,实际上只有3组解。


这三组解是循环的。

再来看这样一个1阶循环排列


虽然这个排列的阶数小于元素的阶数,但是0仍然是上面那个方程的解,读者可以自行验证。

也就是说如果是一个n阶循环排列,是一个m阶循环排列,如果m | n,则在n到m之间能够建立m个满足题意的映射

所以我们需要将排列a和排列b分解成一个个的循环排列,然后暴力搜索一遍即可。

代码如下:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>

using namespace std;

const int MAX_N = 100005;

void f(vector<int>& v, int a[], int n)
{
    int mark[MAX_N] = {0};
    for (int i = 0; i < n; i++)
    {
        if (!mark[i])
        {
            mark[i] = 1;
            int t = a[i];
            int cnt = 1;
            while (t != i)
            {
                mark[t] = 1;
                t = a[t];
                cnt++;
            }
            v.push_back(cnt);
        }
    }
}

int main()
{
    //freopen("test.txt", "r", stdin);
    int n, m;
    int Case = 1;
    int a[MAX_N], b[MAX_N];
    while (~scanf("%d%d", &n, &m))
    {
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        for (int i = 0; i < m; i++)
            scanf("%d", &b[i]);
        vector<int> v1;
        f(v1, a, n);
        vector<int> v2;
        f(v2, b, m);
        int ans = 1;
        for (int i = 0; i < v1.size(); i++)
        {
            int tmp = 0;
            for (int j = 0; j < v2.size(); j++)
            {
                if (v1[i] % v2[j] == 0)
                    tmp += v2[j];
            }
            ans *= tmp;
        }
        printf("Case #%d: ", Case++);
        cout << ans << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值