题目大意

对一个初始矩阵进行置换操作,已知经K次置换后得到的矩阵为,求一组可能的。

样例解释

这里只选取第二组样例进行解释。

4 2

3 4 1 2

2 3 4 1

初始矩阵为,根据Sample Output得知置换操作为,第一次置换后得到矩阵,第二次置换后得到矩阵(和给出的一致),因此是一组可能的。

解题思路

考察一个特定的置换操作(我们暂且称这种矩阵为“置换矩阵”),我们将其写成另外一种形式,这样写的好处就是我们能方便的看出有2个循环节,而且我们会发现不管置换多少次,都是循环节内的数相互动了动位置而已。这启发我们,也许可以从置换K次的结果出发,找到其中的循环节,然后反推出置换1次的结果(也就是)。

而且我们发现,其实K次置换也对应的一个置换矩阵。比如,如果K=2就相当于另一个置换矩阵,简写为。不难发现,随着置换次数的增加,置换矩阵的循环节的个数有可能会发生变化,那么有什么变化的规律么?研究一下就会发现,如果置换1次对应的置换矩阵中有一个长度为m的循环节,当置换次数K满足gcd(m,K) = 1时,这个循环节在置换K次对应的置换矩阵中仍是一个长度为m的循环节,否则这个循环节将会变成gcd(m,K)个长度为m/gcd(m,K)的循环节。反过来讲,假设置换K次之后有一个循环节的长度为n,如果gcd(n,K) > 1,那么这个一定是某个长度为m的较长的循环节“分裂”出来,并且必须满足m/gcd(m,K) = n,同时包含他在内至少应有gcd(m,K)个长度为n的循环节(这里只是给出了一个对长度为n的循环节的个数给出了一个较为宽泛的约束,严格的约束会在后面提到);如果gcd(n,K) = 1,那么既有可能是“分裂”出来的,也有可能不是“分裂”出来的,对于此题而言,我们可以认为其不是“分裂”出来的,可以简化问题的求解。

经过上述分析之后,形成了一个大致的解题思路——分情况处理置换K次对应的置换矩阵中的各个循环节。设循环节的长度为n,如果:

  1. gcd(n,K) = 1。那么直接反推出置换1次时对应的置换矩阵即可。
  2. gcd(n,K) > 1。那么这个一定是某个长度为m的较大的循环节“分裂”出来,而且满足m/gcd(m,K) = n。这时,我们需要把gcd(m, K)个长为n小循环节合并成一个长为m的大循环节并反推出置换1次时对应的置换矩阵。

合并循环节的关键:假设长度为n的循环节一共有cnt个,我们要找到一个最小的gcd(m,K)使得m=gcd(m,K)*n成立。如果这个最小的gcd(m, K)是cnt的约数,那么一定有解,将gcd(m, K)个长度为n的小循环节合成一个长度m的大循环即可;否则无解。

如何找到这个最小的gcd(m,K)?不能单纯地认为gcd(m,K) = gcd(n,K),比如n = 2, K = 4,那么gcd(m,K) = gcd(n,K) = 2, m = gcd(m,K)*n = 4,这样就又能推得gcd(m,K) = 4,矛盾。上面那个例子之所以出现矛盾就是因为n承担了一部分公因子,因此我们要让n不承担任何公因子:对于任意一个n里面的素因子p,如果K里面也有p,那么p在K中是多少次方就应当在gcd(m,K)中是多少次方。不过实际写代码的时候没必要按素因子逐个去检查,只要不断地求K和n的公因数d,并将K除以d,直到d = 1为止,将前面所有的d累乘就是gcd(m,K)。

至于怎么根据置换K次时对应的置换矩阵反推出置换1次时对应的置换矩阵,在这里就不细说了,这个不难。

P.S. 实际写代码的时候就会发现其实并不用分情况讨论gcd(n,K) = 1还是gcd(n,K) > 1,因为当gcd(n,K) = 1时求得的最小的gcd(m,K)就是1,而且1是任何数的约数,自然就会认为这个循环节是由1个循环节“分裂”得到的(也就是没“分裂”)。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAXN 10010
typedef std::vector<int> VI;
int N, K, f[MAXN];
std::vector<VI> c; // cycles
bool cmp(VI v1, VI v2) {
return v1.size() < v2.size();
}
int gcd(int x, int y) {
return y == ? x : gcd(y, x % y);
}
bool vis[MAXN];
// find the cycles
void divideCycle() {
c.clear();
memset(vis, , sizeof(vis[]) * (N + ));
for(int i = ; i <= N; i ++) {
if(!vis[i]) {
VI v;
for(int j = i; !vis[j]; j = f[j]) {
vis[j] = true;
v.push_back(j);
}
c.push_back(v);
}
}
std::sort(c.begin(), c.end(), cmp);
}
int ans[MAXN], a[MAXN];
void process() {
int cn = c.size();
for(int i = , j = ; i < cn; i ++) {
if(i == cn - || c[i].size() != c[i + ].size()) {
int n = c[i].size(); // n是小循环节的长度
int t = K, d, g = ; // g是分裂出来的循环节个数
while((d = gcd(n, t)) != ) {
g *= d, t /= d;
}
int m = g * n; // m是大循环节的长度 if((i - j + ) % g == ) {
for(; j <= i; j += g) { // j~j+g-1 合并成一个大循环节
for(int s = ; s < g; s ++) {
for(int id = , loc = s; id < n; id ++, loc = (loc + K) % m) {
a[loc] = c[j + s][id];
}
}
a[m] = a[];
for(int id = ; id < m; id ++) {
ans[a[id]] = a[id + ];
}
}
} else {
printf("Impossible\n");
return ;
}
}
} printf("%d", ans[]);
for(int i = ; i <= N; i ++) {
printf(" %d", ans[i]);
}
printf("\n");
}
int main() {
while(scanf("%d%d", &N, &K) == ) {
for(int i = ; i <= N; i ++) {
scanf("%d", &f[i]);
}
divideCycle();
process();
}
return ;
}

NCPC 2013: Dance Reconstruction的更多相关文章

  1. 2014 UESTC 暑前集训队内赛(1) 解题报告

    A.Planting Trees 排序+模拟 常识问题,将耗时排一个序,时间长的先种,每次判断更新最后一天的时间. 代码: #include <iostream> #include < ...

  2. 2013长沙 G Graph Reconstruction (Havel-Hakimi定理)

    Graph Reconstruction Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge Let there ...

  3. 2013亚洲区域赛长沙站 ZOJ 3732 Graph Reconstruction

    题目链接 Graph Reconstruction 题意 给你无向图每个点的度数, 问是否存在唯一解, 存在输出唯一解, 多解输出两个, 无解输出IMPOSSIBLE 思路 这里用到了 Havel-H ...

  4. Integrate SharePoint 2013 with Team Foundation Server 2012

    Now that SharePoint 2013 is out I want to make sure that I can integrate SharePoint 2013 with Team F ...

  5. ICLR 2013 International Conference on Learning Representations深度学习论文papers

    ICLR 2013 International Conference on Learning Representations May 02 - 04, 2013, Scottsdale, Arizon ...

  6. 2013:Audio Tag Classification - MIREX Wiki

    Contents [hide] 1 Description 1.1 Task specific mailing list 2 Data 2.1 MajorMiner Tag Dataset 2.2 M ...

  7. 论文解读(NWR)《Graph Auto-Encoder via Neighborhood Wasserstein Reconstruction》

    论文信息 论文标题:Graph Auto-Encoder via Neighborhood Wasserstein Reconstruction论文作者:Shaked Brody, Uri Alon, ...

  8. 2013 Asia Changsha Regional Contest---Josephina and RPG(DP)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4800 Problem Description A role-playing game (RPG and ...

  9. SharePoint 2013: A feature with ID has already been installed in this farm

    使用Visual Studio 2013创建一个可视web 部件,当右击项目选择"部署"时报错: "Error occurred in deployment step ' ...

随机推荐

  1. 去除html标签 正则表达式

    /// <summary>        /// 去除html标签        /// </summary>        public static string Clea ...

  2. 2748: [HAOI2012]音量调节

    Description 一个吉他手准备参加一场演出.他不喜欢在演出时始终使用同一个音量,所以他决定每一首歌之前他都要改变一次音量.在演出开始之前,他已经做好了一个列表,里面写着在每首歌开始之前他想要改 ...

  3. 亲子之间,在于看懂,无关耐心zz

    每当有人告诉我:『你对孩子真有耐心!』时,我总会想起我的金项链,当越来越多人说的时候,我就越想找出来,我翻箱倒柜的找,越心急却越找不到,那 一条金项链从我十八岁那一年一直戴在我的脖子上一直到女儿两岁, ...

  4. Linq to sql 语法方法示例

    联表查询,判断追加条件,对集合分页 ) { var data = from m in _db.AppArticleComment join o in _db.AppArticle on m.Artic ...

  5. Exception in thread "http-apr-8080-exec-2"

    设置了catalina.bat.catalina.sh都不起作用MyEclipse中选择菜单Windows---preferences---MyEclipse---Servers---Tomcat-- ...

  6. 写在Python前

    Python是用C编写的一种解释型语言,和shell一样,变量可以直接使用,而且就像C中的宏替换,但是Python同样支持进行底层的调用,可以很容易的和各种语言进行融合,俗称"胶水语言&qu ...

  7. Windows2003 SQL2005解决系统Administrator密码不知道的问题

    Windows2003 SQL2005解决系统Administrator密码不知道的问题 今天上班的时候,有个同事说不知道谁设置了开机密码,那台电脑一直没有开机密码的他现在进不了桌面 那台电脑没有光驱 ...

  8. 【转载】php中iconv函数使用方法

    原文:http://www.phpweblog.net/star65225692/archive/2011/03/23/7524.html     在选择用什么工具开发,唯一的指导标准就是:用最少的人 ...

  9. Atitti.java exp ast java表达式语法ast构造器

    Atitti.java exp ast java表达式语法ast构造器 /atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_sli ...

  10. paip.判断字符是否中文与以及判读是否是汉字uapi python java php

    paip.判断字符是否中文与以及判读是否是汉字uapi python java php   ##判断中文的原理 注意: 中文与汉字CJKV 的区别..日本,韩国,新加坡,古越南等国家也用汉字,但不是中 ...