VIJOS 1516 N连环
来源:互联网 发布:定时鼠标点击软件源码 编辑:程序博客网 时间:2024/04/28 18:21
题意
九连环应该都知道吧!
(1)第 1 环可以自由上下
(2)而上/下第 n 环时(n>1),则必须满足:
(a)第 n-1 个环在架上
(b)前 n-2 个环全部在架下
为了让大家多学点知识,特改此题
输入2个N连环的状态 保证环数小于等于100
第一行是初状态
第二行是末状态
输出一个数,需要的步数n(保证n不超过qword)
分析
九连环的数学模型实际上是格雷码
我们用一串01串表示N连环的一个状态 记最右边的环为第一个环
九连环包括两个操作
A:将最右边的数位反转 例如:00000->00001
B:将最右边的1左边的数位反转 例如:00101->00111 00100->01100
显然,A和B两种操作任何一种重复做两次,01串等价于没有修改
例如:00000–A->00001–A->00000
因此我们只有让A B操作交替执行
才能让初始串得到其他所有操作序列
这正好就是格雷码的直接排列(以二进制为0值的格雷码为第零项,第一项改变最右边的位元,第二项改变右起第一个为1的位元的左边位元,第三、四项方法同第一、二项,如此反复,即可排列出n个位元的格雷码。)
那么只要将本问题的初末格雷码转换为二进制,两个二进制串的数值差就是答案了
而二进制和格雷码之间具有怎样的关系呢
一个二进制串数值增加1,
如果不进位只会造成最末一位数改变
如果进位将会引起该二进制串lowbit的上一位开始的一系列数位变动
如: 101010->101011 100111->101000
将这两条性质与格雷码的直接排列进行对比
我们可以发现,
格雷码串是二进制串的差分
二进制串是格雷码串的前缀
此处的差分和前缀是建立在模2意义下,证明略去
那么根据这个转换性质就可以很快地把题目解决了
代码
#include<cstdio>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fe(i,a,b) for(int i=a;i>=b;i--)unsigned long long ans;bool a[200],b[200];char c[200];int l;int main(){ scanf("%s",c+1); l=strlen(c+1); fo(i,1,l) if (c[l-i+1]=='0') a[i]=0; else a[i]=1; scanf("%s",c+1); fo(i,1,l) if (c[l-i+1]=='0') b[i]=0; else b[i]=1; fe(i,l-1,1){ a[i]=a[i+1]^a[i];//a[i-1]^a[i]; b[i]=b[i+1]^b[i];//b[i-1]^b[i]; } fe(i,l,1){ if ((a[i]==1)&&(b[i]==0)){ ans+=(unsigned long long)1<<(i-1);// fe(j,i-1,1){ if ((a[j]==1)&&(b[j]==0)) ans+=(unsigned long long)1<<(j-1); if ((a[j]==0)&&(b[j]==1)) ans-=(unsigned long long)1<<(j-1); } printf("%I64u\n",(unsigned long long)ans); return 0; } if ((b[i]==1)&&(a[i]==0)){//得到二进制串的数值差 ans+=(unsigned long long)1<<(i-1); fe(j,i-1,1){ if ((a[j]==1)&&(b[j]==0)) ans-=(unsigned long long)1<<(j-1); if ((a[j]==0)&&(b[j]==1)) ans+=(unsigned long long)1<<(j-1); } printf("%I64u\n",(unsigned long long)ans); return 0; } } printf("0\n");//特殊情况的输出 return 0;}
补充
n进制格雷码串同样也是n进制数串的差分
除了格雷码的直接排列外,还有一种镜射排列:
下图可以清晰地展示排列过程(来自wiki)
- VIJOS 1516 N连环
- c++n连环
- 【21.00%】【vijos P1018】智破连环阵
- COGS 336 && Vijos 1018 && NOI2003 智破连环阵
- 连环记
- 连环套
- 九连环
- 九连环问题解决
- [案件追踪]连环陷阱
- 制作IMC连环画册
- 铉——连环
- 九连环的解法
- 七连环切割问题
- 关于九连环
- 九连环问题解决
- poj 1832 连环锁
- 五行连环拳
- 九连环玩法
- Gesture 通过手势实现翻书效果
- 设置Intent.FLAG_ACTIVITY_NEW_TASK和Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED对Activity Stack的影响
- JavaScript强化教程 - 六步实现贪食蛇
- Android 使用Socket实现服务器与手机客户端的长连接五:使用队列封装请求
- android消息通知Noticication使用详解
- VIJOS 1516 N连环
- json,jsonObject , jsonArray 详解
- HashSet和HashMap的底层实现——哈希表、散列表
- CronTrigger
- Python基础知识学习笔记(1)
- 第二章 java基础(二进制与十进制的转换)
- Leetcode第一题--------- Two Sum
- 第二章 java基础(二进制补码)
- 破解Paralles Desktop