牛客算法竞赛入门课第二节习题
Laptop
有问题可能是题目没看懂,就是假如有一台电脑的内存和速度都低于另一台,那么就是被完爆所以我们只需要将电脑用其中一个属性从小到大排序,然后比较另一个属,只要另一个属性也比后面的更小,那么就是被完爆
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; const int MOD = 1e9 + 7; struct node{ int x , y; bool operator <(node &b) const{ return b.x > x; } }a[MAXN]; int main(void){ int n ; cin>>n; for(int i = 1 ; i <= n ; ++i) cin>>a[i].x>>a[i].y; sort(a + 1 , a + n + 1); int ans = 0; // for(int i = 1 ; i <= n ; ++i) // cout<<a[i].x<<" "<<a[i].y<<endl; for(int i = 1 ; i <= n ; ++i){ for(int j = i + 1 ; j <= n ; ++j){ if(a[i].y < a[j].y){ ans++; break; } } } cout<<ans<<endl; return 0; }
大吉大利,今晚吃鸡
如果我们假设$n$个物品需要$f(n)$的话,那么对于过程来说把个东西通过去,需要
把最大移动到,一步
把个东西通过去,需要
把最大移动到,一步
把个东西通过去,需要
合计 得到递推公式,
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; const int MOD = 1e9 + 7; int main(void){ int n; while(cin>>n){ cout<<pow(3 , n) - 1<<endl; } return 0; }
简单的数据结构
直接stl就好了code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; const int MOD = 1e9 + 7; vector<int> v; int main(void){ int n , m; scanf("%d%d", &n, &m); while(m--){ int op , x; scanf("%d" , &op); if(op == 1){ cin>>x; v.insert(v.begin() , x); } else if(op == 2){ v.erase(v.begin()); } else if(op == 3){ cin>>x; v.push_back(x); } else if(op == 4){ v.pop_back(); } else if(op == 5){ reverse(v.begin() , v.end()); } else if(op == 7){ sort(v.begin() , v.end()); } else{ cout<<v.size()<<endl; for(auto it = v.begin() ; it != v.end() ; ++it){ printf("%d%c" , *it , it == v.end() - 1 ? '\n' :' '); } } } return 0; }
栈和排序
要尽可能的让大的数字先输出来,很容易就能知道如果比他后面的数字都大,那么我们在入栈之后立即让他出栈,则得到的序列一定比后出栈的序列更大
code
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 5; int a[MAXN] , maxe[MAXN] , sta[MAXN] , top; int main(void){ int n; scanf("%d" , &n); for(int i = 1 ; i <= n ; ++i) scanf("%d" , &a[i]); for(int i = n ; i > 0 ; --i){ maxe[i] = max(maxe[i + 1] , a[i]); } // for(int i = 1 ; i <= n ; ++i) // cout<<a[i]<<" "; // cout<<endl; // for(int i = 1 ; i <= n ; ++i) // cout<<maxe[i]<<" "; // cout<<endl; for(int i = 1 ; i <= n ; ++i){ sta[++top] = a[i]; while(top && sta[top] > maxe[i + 1]) printf("%d " ,sta[top--]); } return 0; }
吐泡泡
这个题目,啊,一点都不难 ,但是我做了好久,一开始用stl的栈搞了半天做了好久
最后还是手写的栈好用。
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 105; int main(void){ char st[MAXN]; string s; while(cin>>s){ int h = 0; for(int i = 0 ; i < s.size() ; ++i){ if(h == 0) st[++h] = s[i]; else{ if(st[h] == s[i]){ if(s[i] == 'O') h--; else{ st[h] = 'O'; if(h > 1){ if(st[h - 1] == 'O') h-=2; } } } else st[++h] = s[i]; } } for(int i = 1 ; i <= h ; ++i) cout<<st[i]; cout<<endl; } return 0; }
竞赛技巧
简单题 用结构体存 然后重载一下就好了code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 5007; struct node{ int a , b , c; bool operator <(node &k) const{ if(a == k .a){ if(b == k.b) return c < k.c; return b < k.b; } return a < k .a; } }s[MAXN]; int main(void){ int n; cin>>n; for(int i = 1 ; i <= n ; ++i){ cin>>s[i].a>>s[i].b>>s[i].c; } sort(s + 1 , s + n + 1); for(int i = 1 ; i <= n ; ++i){ cout<<s[i].a<<" "<<s[i].b<<" "<<s[i].c<<endl; } return 0; }
老子的全排列呢
STL真好看用。。。next_permutation 求下一个全排列code
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(void){ string s = "12345678"; do{ for(int i = 0 ; i < 8 ; ++i){ cout<<s[i]; if(i != 7) cout<<" "; } cout<<endl; }while(next_permutation(s.begin() , s.end())); return 0; }
逆序数
求逆序对 看了一眼大佬的博客 太秀了。。x = 1e5 + 10 - x;使得越大的数字存的越靠前,所以用query记一下前面有多少个数就可以知道他的逆序对了
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define lowbit(x) x&(-x) const int MAXN = 2e5 + 10; int sum[MAXN] , cnt = MAXN - 1; void add(int x){ while(x <= cnt){ sum[x]++; x+=lowbit(x); } } int query(int x , int ans = 0){ while(x){ ans += sum[x]; x -=lowbit(x); } return ans; } int main(void){ int n; cin>>n; ll ans = 0; for(int i = 1 ; i <= n ; ++i){ int x; cin>>x; x = 1e5 + 10 - x; ans += query(x - 1); add(x); } cout<<ans<<endl; return 0; }
The Biggest Water Problem
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(void){ ll n; cin>>n; while(n > 10){ ll ans = 0; while(n){ ans += n%10; n /= 10; } n = ans; } cout<<n<<endl; return 0; }
小C的记事本
用c++自带的string就可以解决绝大多数问题操作4我们可以用一个栈,(因为他是回溯到上一次修改字符串的操作)每一次操作都是将一个新的串压进去,然后需要回溯的时候,就只要把栈顶弹出去就好了
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1e5 + 7; stack<string> st; string tmp; int op , n , k; int main(void){ ios::sync_with_stdio(false);cin.tie(0); cout.tie(0); while(cin>>n){ while(st.size()) st.pop(); st.push(" "); while(n--){ cin>>op; if(op == 1){ cin>>tmp; st.push(st.top() + tmp); } else if(op == 2){ cin>>k; tmp = st.top(); tmp.erase(tmp.size() - k , k); st.push(tmp); } else if(op == 3){ cin>>k; string temp = st.top(); cout<<temp[k]<<endl; } else if(op == 4) st.pop(); } } return 0; }
分数线划定
有两个坑点:1,最后如果划到的分数线的下一位和分数线相同,也应该被算进去
2,即有可能出现人不够,即的情况,特判一下即可
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 5000 + 7; struct node{ int a,b; bool operator <(node &k) const{ if(b == k.b) return a < k.a; return b > k .b; } }s[MAXN]; int main(void){ int n , m; cin>>n>>m; for(int i = 1 ; i <= n ; ++i) cin>>s[i].a>>s[i].b; sort(s + 1 , s + n + 1); int ans = m * 1.5; int i = ans + 1; while(s[ans].b == s[i].b && i <= n){ ans++; i++; } if(ans > n){ cout<<s[n].b<<" "<<n<<endl; } else{ cout<<s[ans].b<<" "<<ans<<endl; } for(i = 1 ; i <= ans && i <= n; ++i){ cout<<s[i].a<<" "<<s[i].b<<endl; } return 0; }
FBI树
我的做法是先把这个字符串赋给底层的值,然后向上维护树
然后然后,我是!我是!我是***
2的十次方的正确写法:1<<10 而不是 2^10
code
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int mod=1e9+7; const int MAXN = 1<<10 +5; char k[MAXN] ={0}, post[MAXN] = {0}; int cnt = 1; void postorder(int i){ if(k[i]){ postorder(i * 2); postorder(i * 2 + 1); post[cnt++] = k[i]; } } ll qpow(ll a , ll b){ ll ans = 1; while(b){ if(b & 1) ans = ans * a % mod; a = a*a % mod; b >>= 1; } return ans; } int main(void){ string s = ""; int n; cin>>n; cin>>s; for(int i = qpow(2 , n) , j = 0 ; j < s.size() ; ++i , ++j){ if(s[j] == '1') k[i] = 'I'; else k[i] = 'B'; } //for(int i = 1 ; i <= 15 ;++i) // cout<<k[i]; //cout<<endl; for(int i = n - 1; i >= 0 ; --i){ for(int j = qpow(2 , i) ; j < qpow(2 , i + 1) ; j++){ if(k[2 * j] == k[2 * j + 1]) k[j] = k[2 * j]; else k[j] = 'F'; //cout<<k[j]<<k[2 * j]<<k[2 * j + 1]<<j<<2 * j<<2 * j + 1<<endl; } } //for(int i = 1 ; i <= 15 ;++i) // cout<<k[i]; //cout<<endl; postorder(1); for(int i = 1 ; i < qpow(2 , n + 1) ; ++i){ printf("%c", post[i]); } cout<<endl; return 0; }
指纹锁
挺简单的一个题目 是我想复杂了删除操作 如果x处没有指纹 那么久不会删除
再加上出现重合部分就不会录入
所以根本不存在出现一次删两个及以上的可能,只有可能被x处这个位置的指纹被删
然后我还模拟了半天 准备用线段树写。。。
实际上只需要一个简单的set重载一下就好了
code
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) int n , k , x; string s; struct cmp{ bool operator() (const int& a , const int& b) const { if(abs(a - b) <= k ) return false; return a < b; } }; int main(void){ js; cin>>n>>k; set<int , cmp> st; while(n--){ cin>>s>>x; if(s == "add") st.insert(x); else if(s == "del") st.erase(x); else{ if(st.find(x) != st.end()) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } return 0; }
新建 Microsoft Office Word 文档
用两个set进行操作,一个保存已经建立了的,另一个保存删除了的每一次New就先看看有没有之前删除了,有的话就先建立那个,没有再继续往后新建
code
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; int main(void){ int n; set<int> st1,st2; int i = 0 , j = 0; cin>>n; while(n--){ string s; cin>>s; if(s == "New"){ i++; if(st2.empty()){ cout<<i - j<<endl; st1.insert(i - j); } else{ st1.insert(*st2.begin()); cout<<*st2.begin()<<endl; st2.erase(st2.begin()); } } else{ int k; cin>>k; if(st1.find(k) != st1.end()){ st1.erase(k); cout<<"Successful"<<endl; st2.insert(k); j++; } else cout<<"Failed"<<endl; } } return 0; }
区区区间间间
code
#include<bits/stdc++.h> #define int long long using namespace std; int a[100005]; int l[100005],r[100005],n,ans; void solve() { for(int i=1;i<=n;++i) { int j=i; while(j>1&&a[j-1]<=a[i]) j=l[j-1]; l[i]=j; } for(int i=n;i;--i) { int j=i; while(j<n&&a[j+1]<a[i]) j=r[j+1]; r[i]=j; } for(int i=1;i<=n;++i) { ans+=a[i]*(r[i]-l[i]); ans+=a[i]*(i-l[i])*(r[i]-i); } } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; cin>>t; while(t--) { cin>>n; ans=0; for(int i=1;i<=n;++i) cin>>a[i]; solve(); for(int i=1;i<=n;++i) a[i]=-a[i]; solve(); cout<<ans<<endl; } }
兔子的逆序对
因为我们操作$[l,r]$这个区间,受影响的的逆序对只有$[l,r]$之间的,其他的都没有影响假设原来有个逆序对,区间之间原来有个逆序对,那么我们翻转之后
就变成了
即减去原先的逆序对个数然后加上顺序对个数
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define lowbit(x) x&(-x) const int MAXN = 1e5 + 7; int c[MAXN] , n , m; ll t = 0; void add(int i , int x){ for(; i <= n ; i += lowbit(i)){ c[i] += x; } } ll quary(int i){ ll sum = 0; for(; i ; i -=lowbit(i) ) sum += c[i]; return sum; } int main(void){ scanf("%d" , &n); for(int i = 1 ; i <=n ;++i){ int j; scanf("%d" , &j); t += quary(n) - quary(j - 1); add( j , 1); } scanf("%d" , &m); int ans = t & 1; while(m--){ ll l , r; scanf("%lld%lld" , &l , &r); t = (r - l) * (r - l + 1) >> 1; ans ^= t & 1; if(ans) printf("dislike\n"); else printf("like\n"); } return 0; }
华华教月月做数学
快速幂算法通常用在求 A^B%C 的时候,因为当B足够大的时候 n与logn 的差距就非常巨大了。并且B十分巨大的时候通常我们已经存不下这个数值了。所以一般要对一个C 取模。
如果B十分大,那么有可能会产生a的2^n次方时比 long long 还大。这时就有可能输出负数也就是溢出了。所以这个时候可以用加法来模拟乘法,并且每次相加都对C取模,这样就不会溢出了。
加法模拟乘法:
列如:求75:
n=5的二进制是101,
此时n为奇数,则ans=ans+tmp;tmp=tmp+tmp;n右移一位;(ans=0+7,tmp=72)
此时n为偶数,则直接tmp=tmp+tmp;n右移一位;(ans=7,tmp=74)
此时n为奇数,则ans=ans+tmp;tmp=tmp+tmp;n右移一位;(ans=7+74,tmp=78);
快速幂算法:https://blog.csdn.net/wuyileiju__/article/details/81056150
列如求5^19:
n=19的二进制是10011,
此时n为奇数,则ans=anstmp;tmp=tmptmp;n右移一位;(ans=15,tmp=55=25)
此时n为奇数,则ans=anstmp;tmp=tmptmp;n右移一位;(ans=525,tmp=2525)
此时n为偶数,则直接tmp=tmptmp;n右移一位;(ans=125,tmp=625625)
此时n为偶数,则直接tmp=tmptmp;n右移一位;(ans=125,tmp=390625390625)
此时n为奇数,则ans=anstmp;tmp=tmptmp;n右移一位;(ans=125390625390625,tmp=(390625390625)^2);
code
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll pow_mul(ll a , ll b , ll mod){ ll ans = 0 ; while(b){ if(b&1) ans = (ans + a) % mod; a = (a + a) % mod; b>>=1; } return ans; } ll pow_mod(ll a , ll b , ll mod){ ll ans = 1; while(b){ if(b&1) ans = pow_mul(ans , a , mod); a = pow_mul(a, a , mod); b >>= 1; } return ans; } int main(void){ ll t, a, b, p; scanf("%d" , &t); while(t--){ scanf("%lld%lld%lld" , &a , &b , &p); printf("%lld\n" , pow_mod(a , b, p)); } return 0; }
表达式计算4
又是模拟。。实在是太麻烦了,可以用python的eval来求
只要手动改一下出题人卡的地方就行了
code
def deal(a): a = a.replace('^','**') a = a.replace(' ','') a = a.replace('()','') a = a.replace('/','//') #注意整除 cnt = 0 r = [] for i in range(len(a)): if a[i] == '(': cnt+=1 elif a[i] == ')': if cnt == 0: r.append(i) else: cnt-=1 la = list(a) for i in r: la.pop(i) n = len(la) cnt = 0 l = [] for i in range(n): if la[n - 1 - i] == ')': cnt+=1 elif la[n - 1 - i] == '(': if cnt == 0: l.append(n - 1 - i) else: cnt-=1 for i in l: la.pop(i) a = ''.join(la) return a s = input() s = deal(s) print(eval(s))
Sliding Window
题意很简单 就是求区间里的最大值和最小值这里我们使用单调队列来做
用数组模拟单调队列 首先就是理解为啥用单调队列
就用题目中的例子举例
code
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1e6 + 7; int a[MAXN] , que[MAXN]; int main(void){ int n , m; scanf("%d%d" , &n , &m); for(int i = 1 ; i <= n ; ++i) scanf("%d" , &a[i]); int l = 0 , r = 0; que[r++] = 1; if(m == 1) printf("%d ", a[1]); for(int i = 2 ; i <= n ; ++i){ if(r > l && i - que[l] >= m) ++l; while(r > l && a[que[r - 1]] >= a[i] ) --r; que[r++] = i; if(i >= m) printf("%d " , a[que[l]]); } cout<<endl; l = r =0; que[r++] = 1; if(m == 1) printf("%d " , a[1]); for(int i = 2 ; i <= n ; ++i){ if(r > l && i - que[l] >= m) ++l; while(r > l && a[que[r - 1]] <= a[i]) --r; que[r++] = i; if(i >= m) printf("%d " , a[que[l]]); } cout<<endl; return 0; }
Raid
分治的运用,计算不同类型的点的最近距离将点按照x分成两组,通过递归来求最近距离
code
#include<cstdio> #include <algorithm> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include<cmath> #include<cstring> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; typedef unsigned long long ull; typedef long double ld; const ll MOD = 1e9 + 7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void write(ll x) { if (!x) { putchar('0'); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline int lowbit(int x) { return x & (-x); } const int N = 1e5 + 7; const int INF = 0x3f3f3f3f; struct node{ int x , y; int k; bool operator < (const node& b) const { if(x != b.x) return x < b.x; return y < b.y; } }a[N<<1]; double dis(int x , int y){ return sqrt(1.0 * (a[x].x - a[y].x) * (a[x].x - a[y].x) + 1.0 * (a[x].y - a[y].y) * (a[x].y - a[y].y)); } double solve(int l ,int r){ if(l == r) return INF; int mid = l + r >> 1; double ans = INF; ans = min(ans , min(solve(l , mid) , solve(mid + 1 , r))); for(int i = mid ; i >= l ; --i){ if(dis(mid , i) > ans) break; for(int j = mid ; j <=r ; ++j){ if(dis(j , i) > ans) break; if(a[j].k != a[i].k) ans = min(ans , dis(i , j)); } } return ans; } int main(void){ int T = read(); while(T--){ int n = read(); for(int i = 1 ; i <= n ; ++i) a[i].x = read() , a[i].y = read() , a[i].k = 0; for(int i = n + 1 ; i <= 2 * n ; ++i) a[i].x = read() , a[i].y = read() , a[i].k = 1; sort(a + 1 , a + 1 + 2 *n); printf("%.3f\n" , solve(1 , 2 * n)); } return 0; }
Efficient Solutions
这个题目和前面的那个完爆电脑的有点相似
题意就是一个人有俩个数值,按顺序读入,如果这个人的某一个数值是最低的,那么他就会被记录下来,如果都不是最低的,那就会被排除掉,我们可以使用set按照x排序,然后比较y,如果y小于set最前面的,那么就会保存下来,因为会出现重复的值,所以我们使用multiset
然后我可能是个***吧,漏了一个#都没注意,还交了好多发。。。
code
#include<bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; typedef unsigned long long ull; typedef long double ld; const ll MOD = 1e9 + 7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void write(ll x) { if (!x) { putchar('0'); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline int lowbit(int x) { return x & (-x); } const int N = 1e5 + 7; const int INF = 0x3f3f3f3f; struct node{ int x, y; bool operator <(const node& b) const{ if(x == b.x) return y < b.y; return x < b.x; } }; int main(void){ int T; cin>>T; int cnt = 1; multiset<node> st; while(T--){ int n; st.clear(); cin>>n; if(cnt > 1) cout<<endl; cout<<"Case #"<<cnt++<<":"<<endl; for(int i = 1 ; i <= n ; ++i){ int x , y; cin>>x>>y; node t = {x , y}; multiset<node>::iterator it = st.lower_bound(t); if(it == st.begin() || (--it)->y > y){ st.insert(t); it = st.upper_bound(t); while(it != st.end() && it->y >= y) st.erase(it++); } cout<<st.size()<<endl; } } return 0; }
Golf Bot
用到了bitset专门写了一篇博客介绍 博客链接Bits
就是一个裸的汉诺塔问题,然后将他的过程模拟出来即可code
#include<bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; typedef unsigned long long ull; typedef long double ld; const ll MOD = 1e9 + 7; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void write(ll x) { if (!x) { putchar('0'); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline int lowbit(int x) { return x & (-x); } int n , m; int t[3][12], width; string _begin , _str , str; int cost[5]; inline void print(){ for(int floor = n , pos , len ; floor ; floor--){ str = _str; for(int i = 0 ; i < 3 ; ++i){ if(cost[i] >= floor){ len = 2 * t[i][floor] + 1; pos = width * i + i + 1 + (width - len) / 2; for(int j = pos + 1 ; j <= pos + len ; j++) str[j - 1] = '*'; } } cout<<str<<"\n"; } } inline void move(int a , int b){ t[b][++cost[b]] = t[a][cost[a]--]; cout<<_begin; print(); } void hanoi(int a , int b , int x) { if(x == 1){ move(a , b); return ; } hanoi(a , 3 - a - b , x - 1); move(a , b); hanoi(3 - a - b , b , x - 1); } int main(void){ cin>>n; m = 6 * n + 7; for(int i = 1 ; i <= n ; ++i) t[0][i] = n - i + 1; cost[0] = n; for(int i = 0 ; i < m ; ++i){ _begin += '.'; _str+='.'; } width = 2 * n + 1; _str[width / 2 + 1] = _str[width + 2 + width / 2] = _str[width * 2 + 3 + width / 2] = ' |'; _begin += '\n' + _str + '\n'; cout<<_begin; print(); string tmp; for(int i = 0 ; i < m ; ++i) tmp += '-'; _begin = tmp + '\n' + _begin; (n & 1) ? hanoi(0 , 1, n) : hanoi(0 , 2 ,n); return 0; }