置换群快速幂 学习小结 #by nobody

这篇博客主要记录了作者在解决数学题hdu 4259时,遇到的置换群问题。通过poj1026题目,介绍了如何利用置换群的周期性进行字符串加密的快速幂算法。博客内容将持续更新,分享解题心得。

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

本小结会不断更新,转载注明出处:http://blog.youkuaiyun.com/xdu_truth/article/details/8040080


上个月在hdu热身赛中遇到一个数学题(hdu 4259),本来以为是个找规律的题,想了一下午没想出来。

后来看了解答,觉得好神奇的样子。这几天自学了一下置换群才恍然大悟那题是个很基础的置换群的题。
数学真是博大精深啊。。


结论一:一个长度为l的循环T,l是k的倍数,则T是k个循环的乘积,每个循环分别是循环T中下标i mod k=0,1,2…的元素按顺序的连接。
结论二:一个长度为l的循环T,gcd(l,k)=1,则T是一个循环,与循环T不一定相同。
结论三:一个长度为l的循环T,T是gcd(l,k)个循环的乘积,每个循环分别是循环T中下标i mod gcd(l,k)=0,1,2…的元素的连接。
参见论文《置换群快速幂运算+研究与探讨》和《组合数学》最后一章


下面是一些刷题小结,我会不断更新

----------------------------------------------------------纯洁的分割线----------------------------------------------------------------------

poj 3270
一个关于排序的经典应用,题目和解析可以参见黑书P247例题。
附代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct circle
{
    int t,k,sum;
    circle(){sum = 0;k = 0;t = 1<<30;}
};
int a[10100],b[10100];
int flag[10100];
int n;


int main()
{
    //freopen("input.txt","r",stdin);


    while(~scanf("%d",&n))
    {
        int m = 1<<30;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            b[i] = a[i];
            m = min(m,a[i]);
        }
        sort(b,b+n);


        circle c[10100];
        int tot = 0;
        memset(flag,false,sizeof(flag));
        for(int i=0;i<n;i++)
        {
            if(flag[i])continue;
            flag[i] = true;
            if(a[i] == b[i])continue;
            c[tot].sum += a[i];
            c[tot].t = a[i];
            c[tot].k++;
            int temp = b[i];
            while(temp != a[i])
            {
                c[tot].k++;
                c[tot].sum += temp;
                c[tot].t = min(c[tot].t,temp);
                for(int j=0;j<n;j++)
                {
                    if(a[j]!= temp || flag[j])continue;
                    flag[j] = true;
                    if(a[j]==b[j])continue;
                    temp = b[j];
                    break;


                }
            }
            tot++;


        }
        int cost = 0;
        for(int i=0;i<tot;i++)
        {
            cost += c[i].sum+min((c[i].k - 2)*c[i].t,c[i].t + (c[i].k+1)*m);
   //黑书上最后的那个公式,注意它的推导。
        }
        printf("%d\n",cost);
    }
    return 0;
}
---------------------------------------------------------------华丽的分割线---------------------------------------------------------------------------------------

poj1026

问题描述:给一个置换群, 然后 给出一个字符串 需要让你帮他加密M次
其中原串不足的地方用‘ ’补足
解析:最简单的置换群,找周期就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[210],b[210],len[210];
char str[210];
int n,k;
int main()
{
    freopen("input.txt","r",stdin);
    while(scanf("%d",&n),n)
    {
            for(int i=0;i<n;i++)
            {
                int t;
                scanf("%d",&t);
                t--;
                a[t] = i;
            }

            memset(len,0,sizeof(len));
            for(int i=0;i<n;i++)
            {
                int t = a[i];
                len[i]++;
                while(a[i]!=a[t])
                {
                    len[i]++;
                    t = a[t];
                }
            }

            while(scanf("%d",&k),k)
            {
                char ch;
                scanf("%c",&ch);//
                int cnt = 0;
                while(1)
                {
                    scanf("%c",&str[cnt]);
                    if(str[cnt]=='\n')break;
                    cnt++;

                }
                if(cnt < n)
                {
                    for(int i=cnt;i<n;i++)
                        str[i] = ' ';
                }
                for(int i=0;i<n;i++)
                    b[i] = i;
                for(int i=0;i<n;i++)
                    for(int j=0;j<k%len[i];j++)
                        b[i] = a[b[i]];

                for(int i=0;i<n;i++)
                    printf("%c",str[b[i]]);
                printf("\n");

            }
            printf("\n");


    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值