6760: 九连环
时间限制: 1 Sec 内存限制: 128 MB提交: 642 解决: 104
[提交] [状态] [讨论版] [命题人:admin]
题目描述
九连环是一种源于中国的传统智力游戏。如图所示,九个圆环套在一把“剑”上,并且互相牵连。游戏的目标是把九个圆环从“剑”上卸下。
圆环的装卸需要遵守两个规则。
第一个(最右边)环任何时候都可以装上或卸下。
如果第k个环没有被卸下,且第k个环右边的所有环都被卸下,则第k+1个环(第k个环左边相邻的环)可以任意装上或卸下。
与魔方的千变万化不同,解九连环的最优策略是唯一的。为简单起见,我们以“四连环”为例,演示这一过程。这里用1表示环在“剑”上,0表示环已经卸下。
初始状态为1111,每部的操作如下:
1101(根据规则2,卸下第2个环)
1100(根据规则1,卸下第1个环)
0100(根据规则2,卸下第4个环)
0101(根据规则1,装上第1个环)
0111(根据规则2,装上第2个环)
0110(根据规则1,卸下第1个环)
0010(根据规则2,卸下第3个环)
0011(根据规则1,装上第1个环)
0001(根据规则2,卸下第2个环)
0000(根据规则1,卸下第1个环)
由此可见,卸下“四连环”至少需要10步。随着环数增加,需要的步数也会随之增多。例如卸下九连环,就至少需要341步。
请你计算,有n个环的情况下,按照规则,全部卸下至少需要多少步。
![](http://exam.upc.edu.cn/upload/image/20180501/20180501214523_64847.jpg)
第一个(最右边)环任何时候都可以装上或卸下。
如果第k个环没有被卸下,且第k个环右边的所有环都被卸下,则第k+1个环(第k个环左边相邻的环)可以任意装上或卸下。
与魔方的千变万化不同,解九连环的最优策略是唯一的。为简单起见,我们以“四连环”为例,演示这一过程。这里用1表示环在“剑”上,0表示环已经卸下。
初始状态为1111,每部的操作如下:
1101(根据规则2,卸下第2个环)
1100(根据规则1,卸下第1个环)
0100(根据规则2,卸下第4个环)
0101(根据规则1,装上第1个环)
0111(根据规则2,装上第2个环)
0110(根据规则1,卸下第1个环)
0010(根据规则2,卸下第3个环)
0011(根据规则1,装上第1个环)
0001(根据规则2,卸下第2个环)
0000(根据规则1,卸下第1个环)
由此可见,卸下“四连环”至少需要10步。随着环数增加,需要的步数也会随之增多。例如卸下九连环,就至少需要341步。
请你计算,有n个环的情况下,按照规则,全部卸下至少需要多少步。
输入
输入第一行为一个整数m ,表示测试点数目。
接下来m行,每行一个整数n。
接下来m行,每行一个整数n。
输出
输出共m行,对应每个测试点的计算结果。
样例输入
3
3
5
9
样例输出
5
21
341
提示
对于10%的数据,1≤n≤10。
对于30%的数据,1≤n≤30。
对于100%的数据,1≤n≤105,1≤m≤10。
来源/分类
思路:通过找规律可知,n连环的最少步数是⌊(2^(n+1))/3⌋,剩下的就是套板子!
AC代码:
#include <bits/stdc++.h> #define enter putchar(' ') #define space putchar(' ') using namespace std; template <class T> void read(T &x) { char c; bool op=0; while(c=getchar(),c<'0'||c>'9') { if(c=='-')op=1; } x=c-'0'; while(c=getchar(),c>='0' && c<='9') { x=x*10+c-'0'; } if(op==1) x=-x; } template <class T> void write(T x) { if(x < 0) putchar('-'),x=-x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 150000; const double PI = acos(-1); int T,x; struct cp { double a,b; cp(){} cp(double x, double y):a(x),b(y){} cp operator + (const cp &obj) const { return cp(a+obj.a,b+obj.b); } cp operator - (const cp &obj) const { return cp(a-obj.a,b-obj.b); } cp operator * (const cp &obj) const { return cp(a*obj.a-b*obj.b,a*obj.b+b*obj.a); } }inv[N],omg[N]; void init(int n) { for(int i=0;i<n;i++) { omg[i]=cp(cos(2*PI/n*i),sin(2*PI/n*i)); inv[i]=cp(omg[i].a,-omg[i].b); } } void fft(cp *a,int n,cp *omg) { int lim = 0; while((1<<lim)<n) lim++; for(int i=0;i<n;i++) { int t=0; for(int j=0;j<lim;j++) { if(i>>j&1) t|=1<<(lim-j-1); } if(i<t) swap(a[i],a[t]); } for(int l=2; l<=n; l<<=1) { int m=l/2; for(cp *p=a; p!=a+n; p+=l) { for(int i=0; i<m; i++) { cp t=omg[n/l*i]*p[i+m]; p[i+m]=p[i]-t; p[i]=p[i]+t; } } } } struct big { int g[N],len; big() { memset(g,0,sizeof(g)); len=1; } big(int x) { memset(g,0,sizeof(g)); len=0; if(!x) { len=1; return; } while(x) g[len++]=x%10,x/=10; } void out() { for(int i=len-1; i>=0; i--) { printf("%d",g[i]); } enter; } void operator /= (int x) { int sum=0, newlen=0; for(int i=len-1; i>=0; i--) { sum=sum*10+g[i]; if(sum<x) g[i]=0; else { if(!newlen) newlen=i+1; g[i]=sum/x; sum%=x; } } len=max(newlen,1); } void operator *= (const big &b) { static cp A[N], B[N]; int newlen=len+b.len-1,n=1; while(n<newlen) n<<=1; for(int i=0; i<n; i++) { A[i]=cp(i<len ? g[i]:0,0); B[i]=cp(i<b.len ? b.g[i]:0,0); } init(n); fft(A, n, omg); fft(B, n, omg); for(int i=0; i<n; i++) { A[i]=A[i]*B[i]; } fft(A, n, inv); for(int i=0; i<newlen; i++) { g[i]=(int)floor(A[i].a/n+0.5); } g[len=newlen]=0; for(int i=0; i<len; i++) { g[i+1]+=g[i]/10,g[i]%=10; } if(g[len]) len++; } }ret,a; int main() { read(T); while(T--) { read(x),x++; ret=big(1),a=big(2); while(x) { if(x&1) ret*=a; a*=a; x>>=1; } ret/=3; ret.out(); } return 0; }