NOIP 2005 篝火晚会 COGS 112(只是用到置换的一个小概念而已)
2015-09-25 14:32
375 查看
COGS上的标签是图论+群论。。(-__-)我可以说是乱搞吗。
我们首先要构建出末态的环,如果构建不出来(比如A想和B相邻而B不想和A相邻)则无解。构建出来后我们把它变成一个序列。把初态也变成一个序列,就成了这样:
A1, A2, A3, A4……
B1, B2, B3, B4……
为什么初态用一个数组表示而不直接1,2,3,4……呢?因为把环拆开可以有不同的断点,也可以有两个方向去读取这个环。对于上面状态的两个序列,从初态变为末态要花费的代价为Σ(Ai != Bi),这里应该就是涉及群论的地方了,应该不难想明白这个代价吧。
那么我们的任务就明确了,初态末态都可以拆成2*n中序列,代价就是两个序列有多少对不同的对应元素,不过不需要2*n个与2*n个比较,只需要2*n个与1个比较即可。但时间上仍然无法接受。每次调整都是把i位置变到i+1,把n变到1(和题目中描述的指令一样),变完后再翻转序列再来一次最终得到这2*n个序列,再O(n)比较会T。
不过思考每次调整的本质,可以说是把每个数与它对应的位置的距离改变,比如说:
1 2 3 4 5
2 1 4 5 3
dis[i]表示i在末态中是初态中位置右边的第几个,dis[i]:
1 4 2 4 4
那么我们调整一次末态(初态也可以),变成:
3 2 1 4 5
那么dis数组就变成了:
2 0 3 0 0
dis[i] == 0就表示位置相同,这时只有两个位置不同,那么代价就是2,就是这一问的答案。
所以就比较显然了,我们再搞一个数组d[i]表示距离为i的数的个数,找出最大值num,那么就是说在当前初态与当前末态中,距离为num的数的个数最多,那么我们把每个数都右移num个位置,或者调整num次就可以得到上下元素不同的对数最小的情况。
当然这只是n个序列的,还需要把最开始求出的末态数组反转一下,同样的过程,就是另外n个序列的。num取max,最终n-num就是答案。
更像乱搞么,原谅蒟蒻对群论的理解不多。
我们首先要构建出末态的环,如果构建不出来(比如A想和B相邻而B不想和A相邻)则无解。构建出来后我们把它变成一个序列。把初态也变成一个序列,就成了这样:
A1, A2, A3, A4……
B1, B2, B3, B4……
为什么初态用一个数组表示而不直接1,2,3,4……呢?因为把环拆开可以有不同的断点,也可以有两个方向去读取这个环。对于上面状态的两个序列,从初态变为末态要花费的代价为Σ(Ai != Bi),这里应该就是涉及群论的地方了,应该不难想明白这个代价吧。
那么我们的任务就明确了,初态末态都可以拆成2*n中序列,代价就是两个序列有多少对不同的对应元素,不过不需要2*n个与2*n个比较,只需要2*n个与1个比较即可。但时间上仍然无法接受。每次调整都是把i位置变到i+1,把n变到1(和题目中描述的指令一样),变完后再翻转序列再来一次最终得到这2*n个序列,再O(n)比较会T。
不过思考每次调整的本质,可以说是把每个数与它对应的位置的距离改变,比如说:
1 2 3 4 5
2 1 4 5 3
dis[i]表示i在末态中是初态中位置右边的第几个,dis[i]:
1 4 2 4 4
那么我们调整一次末态(初态也可以),变成:
3 2 1 4 5
那么dis数组就变成了:
2 0 3 0 0
dis[i] == 0就表示位置相同,这时只有两个位置不同,那么代价就是2,就是这一问的答案。
所以就比较显然了,我们再搞一个数组d[i]表示距离为i的数的个数,找出最大值num,那么就是说在当前初态与当前末态中,距离为num的数的个数最多,那么我们把每个数都右移num个位置,或者调整num次就可以得到上下元素不同的对数最小的情况。
当然这只是n个序列的,还需要把最开始求出的末态数组反转一下,同样的过程,就是另外n个序列的。num取max,最终n-num就是答案。
更像乱搞么,原谅蒟蒻对群论的理解不多。
#include <cstdio> #include <algorithm> #include <cstring> #define M 50005 using namespace std; int n, num, a[M], d[M], q[M][2]; bool vis[M]; void get(int &x){ char c = getchar(); x = 0; while(c < '0' || c > '9') c = getchar(); while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar(); } bool sec(int i, int j){ a[i] = j; vis[j] = 1; if(i == n){ return (q[j][1]==a[i-1]&&q[j][0]==a[1]) ||(q[j][0]==a[i-1]&&q[j][1]==a[1]); } if(!vis[q[j][1]]){ return sec(i+1, q[j][1]); } if(!vis[q[j][0]]) { return sec(i+1, q[j][0]); } return 0; } int main() { get(n); for(int i = 1; i <= n; i++){ get(q[i][1]); get(q[i][0]); } if(!sec(1, 1)){ printf("-1"); return 0; } for(int i = 1; i <= n; i++){ int dis = (a[i]-i+n)%n; d[dis]++; num = max(num, d[dis]); } for(int i = 1; i <= n-i+1; i++){ swap(a[i], a[n-i+1]); } memset(d, 0, sizeof d); for(int i = 1; i <= n; i++){ int dis = (a[i]-i+n)%n; d[dis]++; num = max(num, d[dis]); } printf("%d", n-num); return 0; }
相关文章推荐
- C#默认参数
- 黑马程序员——基础知识——语句结构
- LogUtils的介绍
- Swift - 按钮(UIButton)的用法
- 长尾分布(幂律分布)
- DBWn 进程和 DB_WRITER_PROCESSES/DBWR_IO_SLAVES 参数
- 16-EMM Procedure 6. Handover without TAU - Part 1. Overview of LTE Handover
- OC基础-OC三大基本数据结构-NSDictionary
- java的system.arraycopy()方法
- RJ45接口定义---dog0138
- Swift - 文本标签(UILabel)的用法
- MySQL命令执行sql文件的两种方法
- JS - 循环添加 DropDownList(Select)
- Unity3D之UGUI学习笔记(二):Rect Transform与Anchor
- Deepin 下交换 CapsLock和Ctrl
- 元数据(Metadata)
- Django Meta内部类选项
- git和maven的必要性
- Swift - 文件,文件夹操作大全
- CentOS程序 开机启动设置与chkconfig命令学习