HDOJ-5392 Infoplane in Tina Town(置换群循环节长度)
2015-08-17 16:24
417 查看
求置换群的循环节长度。
除了取模部分,题意和poj2369一样
简而言之,给出一个1—n的排列p[i], p[i]表示把数列中a[]中的第p[i]位转移到第i位
例如n=5时,p[]=4,1 5,2,3,a[]=1,2,3,4,5
进行第一次便后后得到a[]=4,1,5,2,3
再进行一次变换后得到a[]=2,4,3,1,5
再进行一次变换后得到a[]=1,2,5,4,3
再进行一次变换后得到a[]=4,1,3,2,5
再进行一次变换后得到a[]=2,4,5,1,3
再进行一次变换后得到a[]=1,2,3,4,5
模拟一下这个过程会发现,位置(1,2,4)是一个循环,(3,5)是一个循环
那么所有n个元素的循环节就是这些小循环节长度的最小公倍数
找出所有的小循环复杂度为O(n),因为每个位置最多被遍历一次
因为涉及到取模,所以不能直接用lcm(a,b)=a*b/gcd(a,b)
要对所有的循环节长度分解质因数,最后取每个质因数个数的最大值
另外,做这道题的时候发现,普通的输入挂,再输入数据很大时(此题据说输入数据110MB)也有可能拖慢速度(慢了1.5左右)。
如果指数不大的话(最大几十),用快速幂也可能拖慢速度。
除了取模部分,题意和poj2369一样
简而言之,给出一个1—n的排列p[i], p[i]表示把数列中a[]中的第p[i]位转移到第i位
例如n=5时,p[]=4,1 5,2,3,a[]=1,2,3,4,5
进行第一次便后后得到a[]=4,1,5,2,3
再进行一次变换后得到a[]=2,4,3,1,5
再进行一次变换后得到a[]=1,2,5,4,3
再进行一次变换后得到a[]=4,1,3,2,5
再进行一次变换后得到a[]=2,4,5,1,3
再进行一次变换后得到a[]=1,2,3,4,5
模拟一下这个过程会发现,位置(1,2,4)是一个循环,(3,5)是一个循环
那么所有n个元素的循环节就是这些小循环节长度的最小公倍数
找出所有的小循环复杂度为O(n),因为每个位置最多被遍历一次
因为涉及到取模,所以不能直接用lcm(a,b)=a*b/gcd(a,b)
要对所有的循环节长度分解质因数,最后取每个质因数个数的最大值
另外,做这道题的时候发现,普通的输入挂,再输入数据很大时(此题据说输入数据110MB)也有可能拖慢速度(慢了1.5左右)。
如果指数不大的话(最大几十),用快速幂也可能拖慢速度。
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; typedef unsigned long long ULL; const int N =220000; const int MAXN=3000000+100; ULL base=3221225473; int tol; //质因数个数 int a ; //质因数 int px ; //质因数的指数 int pa ; //质因数的指数 int p[MAXN+5];//置换顺序 bool f[MAXN+5];//线性筛数组 bool v[MAXN+5];//访问标签 void init_prime() { tol=0; memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); f[0]=f[1]=1; for(int i=2;i<=MAXN;i++) { if(!f[i]) { a[tol++]=i; if(i>MAXN/i) continue; for(int j=i*i; j<=MAXN; j+=i) f[j]=1; } } } void update_lcm(ULL x) { int i,cnt; memset(px,0,sizeof(px)); cnt=tol-1; for(i=0;i<tol;i++) { while(x%a[i]==0) { px[i]++; x/=a[i]; } if(x==1) { cnt=i; break; } } for(i=0;i<=cnt;i++) pa[i]=max(pa[i],px[i]); } //指数不大的情况下快速幂反而会拖慢速度,不用了 /* ULL quickpow(ULL x,ULL n) { ULL t,res; res=1; t=x; while(n) { if(n&1) res=(res*t)%base; n>>=1; t=(t*t)%base; } return res; } */ void work() { int n,flag,cnt; ULL ans=1; memset(pa,0,sizeof(pa)); scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&p[i]); //找出每个循环的循环节长度 memset(v,0,sizeof(v)); for (int i = 1; i <= n; i++) if(!v[i]) { cnt = 0; flag = i; while (!v[flag]) { cnt++; v[flag] = 1; flag = p[flag]; } if (cnt>1) update_lcm(cnt); } for(int i=0; i<tol; i++) while(pa[i]--) ans=(ans*a[i]) %base; printf("%I64u\n",ans%base); } int main() { int T; init_prime(); scanf("%d",&T); while(T--) work(); return 0; }
相关文章推荐
- Linux Shell编程入门
- open-flash-chart2各种效果
- 详解coredump
- Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同
- java web前端学习网站
- CentOS 7安装Nginx
- 利用Python在堡垒机模式下批量管理后端nginx服务器
- 一段关于Unix与 Linux的暗黑史
- iPhone开发网站、论坛、博客
- openstack 指定创建 vm IP 地址
- 如何修复Linux中出现的“ImportError: No module named wxversion”错误
- unix bsd linux gun 粗略解释
- [HDOJ4349]Xiao Ming's Hope
- CentOS系统下的Hadoop集群(第7期)_Eclipse开发环境设置
- LINUX修改文件名rename
- hdu5392--Infoplane in Tina Town(置换群+质因子分解求最小公倍数)
- cropper .net后台截图
- Linux中fork()函数实例讲解
- 借助Apache Cordova构建混合移动应用程序
- Tomcat容器 web.xml详解