本小结会不断更新,转载注明出处: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;
}