浙江财经大学天梯赛选拔赛题解
现场写的代码,比较乱.....
$1$.[分值:$5$] $5-11$ 编程打印空心字符菱形
模拟一下下即可
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; char s[5]; char m[500][500]; int r ,c ,x,n; int main() { cin>>s>>n; char now=s[0]; if(n==1) { printf("%c\n",now); return 0; } r =1, c=n/2+1, x=n/2+1; while(x--) m[r][c]=now, now++, r++, c--; now=s[0], r=1, c=n/2+1, x=n/2+1; while(x--) m[r][c]=now, now++, r++, c++; now=s[0],r=n, c=n/2+1,x=n/2+1; while(x--) m[r][c]=now,now++, r--, c--; now=s[0],r=n, c=n/2+1,x=n/2+1; while(x--) m[r][c]=now,now++,r--, c++; for(int i=1;; i++) { if(m[1][i]=='\0') printf(" "); else { printf("%c",m[n][i]); break; } } printf("\n"); for(int i=2; i<=n-1; i++) { int g=0; for(int j=1;; j++) { if(m[i][j]=='\0') printf(" "); else { g++; printf("%c",m[i][j]); if(g==2) { printf("\n"); break; } } } } for(int i=1;; i++) { if(m[n][i]=='\0') printf(" "); else { printf("%c",m[n][i]); break; } } printf("\n"); return 0; }
$2$.[分值:$5$] $5-17$ 算术入门之加减乘除
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int a,b; int main() { cin>>a>>b; printf("%d + %d = %d\n",a,b,a+b); printf("%d - %d = %d\n",a,b,a-b); printf("%d * %d = %d\n",a,b,a*b); if(a%b!=0) printf("%d / %d = %.2f\n",a,b,1.0*a/b); else printf("%d / %d = %d\n",a,b,a/b); return 0; }
$3$.[分值:$10$] $5-9$ 输出华氏-摄氏温度转换表
注意输出格式
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int a,b; int main() { cin>>a>>b; if(a>b) { printf("Invalid.\n"); return 0;} printf("fahr celsius\n"); for(int i=a;i<=b;i=i+2) { printf("%d%6.1f\n",i,5.0*(i-32)/9); } return 0; }
$4$.[分值:$10$] $5-14$ 掉入陷阱的数字
模拟。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n; int f[100000]; int get(int x) { int sum=0; while(x) { sum=sum+x%10; x=x/10; } return sum*3+1; } int main() { cin>>n; int now=n; f[now]++; for(int i=1;;i++) { now=get(now); f[now]++; printf("%d:%d\n",i,now); if(f[now]==2) break; } return 0; }
$5$.[分值:$15$] $5-8$ 人民币兑换
暴力枚举
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n; int main() { cin>>n; int ans=0; for(int i=1;i<=100;i++) { for(int j=1;j<=100;j++) { for(int k=1;k<=100;k++) { if(5*i+2*j+1*k==5*1+2*46+1*53&&i+j+k==100) { printf("%d %d %d\n",i,j,k); ans++; if(ans==n) return 0; } } } } return 0; }
$6$.[分值:$15$] $5-18$ 大炮打蚊子
模拟,注意出界的判断
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; char s[500][500]; int n,m; int f[500][500]; bool check(int a,int b) { if(a>=0&&a<n&&b>=0&&b<m) return 1; return 0; } int main() { cin>>n>>m; for(int i=0;i<n;i++) cin>>s[i]; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(s[i][j]=='#') f[i][j]=2; } } int q; cin>>q; while(q--) { int x,y,ans=0; cin>>x>>y; if(f[x][y]) ans++, f[x][y]=0; if(check(x-1,y)&&f[x-1][y]) { f[x-1][y]--; if(f[x-1][y]==0) ans++; } if(check(x+1,y)&&f[x+1][y]) { f[x+1][y]--; if(f[x+1][y]==0) ans++; } if(check(x,y-1)&&f[x][y-1]) { f[x][y-1]--; if(f[x][y-1]==0) ans++; } if(check(x,y+1)&&f[x][y+1]) { f[x][y+1]--; if(f[x][y+1]==0) ans++; } cout<<ans<<endl; } return 0; }
$7$.[分值:$20$] $5-2$ 符号配对
栈。
遇到左括号,压入栈。
遇到右括号 ($1$)如果栈为空那么这个有括号没有左括号与他配对
($2$) 如果栈顶和这个有括号配对,弹出栈顶
($3$)如果栈顶不和这个有括号配对,那么栈顶就是没有右括号和他匹配了
最后如果栈为空,那么输出$YES$;否则还是需要输出栈顶没有右括号和他匹配
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; char s[100000]; stack<int>st; void out(int x) { printf("NO\n"); if(x==1) printf("/*-?\n"); if(x==2) printf("(-?\n"); if(x==3) printf("[-?\n"); if(x==4) printf("{-?\n"); } void OUT(int x) { printf("NO\n"); if(x==1) printf("?-*/\n"); if(x==2) printf("?-)\n"); if(x==3) printf("?-]\n"); if(x==4) printf("?-}\n"); } int main() { int fail=0; while(cin>>s) { int len=strlen(s); if(s[0]=='.'&&len==1) break; if(fail) break; for(int i=0;i<len;) { if(s[i]=='/'&&s[i+1]=='*') { st.push(1); i=i+2; } else if(s[i]=='*'&&s[i+1]=='/') { if(st.empty()||st.top()!=1) { if(st.empty()) OUT(1); else out(st.top()); return 0; } else st.pop(); i=i+2; } else if(s[i]=='(') { st.push(2); i=i+1; } else if(s[i]==')') { if(st.empty()||st.top()!=2) { if(st.empty()) OUT(2); else out(st.top()); return 0; } else st.pop(); i=i+1; } else if(s[i]=='[') { st.push(3); i=i+1; } else if(s[i]==']') { if(st.empty()||st.top()!=3) { if(st.empty()) OUT(3); else out(st.top()); return 0; } else st.pop(); i=i+1; } else if(s[i]=='{') { st.push(4); i=i+1; } else if(s[i]=='}') { if(st.empty()||st.top()!=4) { if(st.empty()) OUT(4); else out(st.top()); return 0; } else st.pop(); i=i+1; } else i++; } } if(st.empty()) printf("YES\n"); else out(st.top()); return 0; }
$8$.[分值:$20$] $5-10$ 说反话-加强版
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> #include<iostream> using namespace std; vector<string>v; int main() { string s; int sz=0; while(cin>>s) { sz++; v.push_back(s); } for(int i=sz-1;i>=0;i--) { cout<<v[i]; if(i>0) cout<<" "; else cout<<endl; } }
$9$.[分值:$25$] $5-3$ 顺序存储的二叉树的最近的公共祖先问题
用数组存二叉树,节点$p$的左儿子为$2*p$,右儿子为$2*p+1$。某节点要往父亲节点走,只要节点编号$/2$即可。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n,a[2000]; int A,B; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; cin>>A>>B; if(a[A]==0) printf("ERROR: T[%d] is NULL\n",A); else if(a[B]==0) printf("ERROR: T[%d] is NULL\n",B); else { while(1) { if(A==B) break; if(A>B) A=A/2; else B=B/2; } printf("%d %d\n",A,a[A]); } return 0; }
$10$.[分值:$25$] $5-4$ 银行排队问题之单队列多窗口服务
模拟,记录一下每个窗口最早空闲的时间即可。最后一组数据大概是错误的。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n,k; struct P { int daoda; int jieshou; int chuli; int likai; }p[2000]; int cklast[30]; int ckans[30]; int main() { memset(cklast,0,sizeof cklast); memset(ckans,0,sizeof ckans); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&p[i].daoda,&p[i].chuli); p[i].chuli = min(60,p[i].chuli); } scanf("%d",&k); for(int i=1;i<=n;i++) { int idx, Find=0; int mn=0x3f3f3f3f; for(int j=1;j<=k;j++) { if(cklast[j]<p[i].daoda) // if(cklast[j]<=p[i].daoda)讲道理是要有等号的,但是加了就错 { p[i].jieshou = p[i].daoda; p[i].likai = p[i].jieshou + p[i].chuli; ckans[j]++; cklast[j] = p[i].likai; Find=1; break; } } if(Find==0) { for(int j=1;j<=k;j++) { if(cklast[j]<mn) { mn=cklast[j]; idx=j; } } p[i].jieshou = mn; p[i].likai = p[i].jieshou + p[i].chuli; ckans[idx]++; cklast[idx] = p[i].likai; } } int sum=0; for(int i=1;i<=n;i++) sum=sum+p[i].jieshou-p[i].daoda; printf("%.1lf ",1.0*sum/n); sum=0; for(int i=1;i<=n;i++) sum=max(sum,p[i].jieshou-p[i].daoda); printf("%d ",sum); sum=0; for(int i=1;i<=n;i++) sum=max(sum,p[i].likai); printf("%d\n",sum); for(int i=1;i<=k;i++) { printf("%d",ckans[i]); if(i<k) printf(" "); } printf("\n"); return 0; }
$11$.[分值:$25$] $5-7$ 城市间紧急救援
最短路,拓扑排序上$dp$。
为了避免写一发最短路上繁琐的$if$判断,我个人比较喜欢先处理出一个只包含最短路的有向无环图。然后在这个有向无环图上用拓扑排序搞$dp$就可以了。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int INF=0x7FFFFFFF; int n,m,s,d; int v[1000]; struct Edge { int a,b,c; }e[300000]; int sz; vector<int>g[1000],t[1000]; int f[1000],disS[1000],disD[1000],pre[1000],GET[1000],in[1000],p[1000]; void add(int A,int B,int C) { e[sz].a=A; e[sz].b=B; e[sz].c=C; g[e[sz].a].push_back(sz); sz++; } void spfaS() { queue<int>Q; for(int i=0;i<n;i++) f[i]=0,disS[i]=INF; disS[s]=0; Q.push(s); f[s]=1; while(!Q.empty()) { int h=Q.front(); Q.pop(); f[h]=0; for(int i=0;i<g[h].size();i++) { int id = g[h][i]; if(disS[h]+e[id].c<disS[e[id].b]) { disS[e[id].b]=disS[h]+e[id].c; if(f[e[id].b]==0) { Q.push(e[id].b); f[e[id].b]=1; } } } } } void spfaD() { queue<int>Q; for(int i=0;i<n;i++) f[i]=0,disD[i]=INF; disD[d]=0; Q.push(d); f[d]=1; while(!Q.empty()) { int h=Q.front(); Q.pop(); f[h]=0; for(int i=0;i<g[h].size();i++) { int id = g[h][i]; if(disD[h]+e[id].c<disD[e[id].b]) { disD[e[id].b]=disD[h]+e[id].c; if(f[e[id].b]==0) { Q.push(e[id].b); f[e[id].b]=1; } } } } } void W() { queue<int>Q; Q.push(s); GET[s]=v[s]; p[s]=1; while(!Q.empty()) { int h=Q.front(); Q.pop(); for(int i=0;i<t[h].size();i++) { int to = t[h][i]; p[to]=p[to]+p[h]; in[to]--; if(GET[h]+v[to]>GET[to]) { GET[to]=GET[h]+v[to]; pre[to]=h; } if(in[to]==0) Q.push(to); } } } int main() { scanf("%d%d%d%d",&n,&m,&s,&d); for(int i=0;i<n;i++) cin>>v[i]; for(int i=1;i<=m;i++) { int A,B,C; cin>>A>>B>>C; add(A,B,C); add(B,A,C); } spfaS(); spfaD(); for(int i=0;i<sz;i++) { if(disS[e[i].a]+disD[e[i].b]+e[i].c == disS[d]) { t[e[i].a].push_back(e[i].b); in[e[i].b]++; } } memset(pre,-1,sizeof pre); W(); printf("%d %d\n",p[d],GET[d]); stack<int>st; int now=d; while(1) { if(now==-1) break; st.push(now); now=pre[now]; } vector<int>ans; while(!st.empty()) { ans.push_back(st.top()); st.pop(); } for(int i=0;i<ans.size();i++) { if(i<ans.size()-1) printf("%d ",ans[i]); else printf("%d\n",ans[i]); } return 0; }
$12$.[分值:$25$] $5-13$ 是否同一棵二叉搜索树
开两个数组存树,然后比较数组是否相同即可。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n,m; int s[2][20000]; void Insert(int x,int y) { int p=1; while(1) { if(y<s[x][p]) { if(s[x][2*p]==-1) { s[x][2*p]=y; break; } else p=2*p; } else { if(s[x][2*p+1]==-1) { s[x][2*p+1]=y; break; } else p=2*p+1; } } } bool check() { for(int i=1;i<10000;i++) { if(s[0][i]!=s[1][i]) return 0; } return 1; } int main() { while(~scanf("%d",&n)) { if(n==0) break; cin>>m; memset(s,-1,sizeof s); int x; cin>>x; s[0][1]=x; for(int i=2;i<=n;i++) { int x; cin>>x; Insert(0,x); } while(m--) { for(int i=0;i<10000;i++) s[1][i]=-1; cin>>x; s[1][1]=x; for(int i=2;i<=n;i++) { int x; cin>>x; Insert(1,x); } if(check()) printf("Yes\n"); else printf("No\n"); } } return 0; }
$13$.[分值:$30$] $5-5$ 银行排队问题之单队列多窗口加$VIP$服务
这题还没写,但是之前写过一个和这题类似的模拟题,较为恶心。1026. Table Tennis (30),我的代码在这里。
$14$.[分值:$30$] $5-6$ 畅通工程之最低成本建设问题
最小生成树。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n,m; int f[2000]; struct Edge { int a,b,c; }e[100000]; bool cmp(Edge a,Edge b) { return a.c<b.c; } int Find(int x) { if(f[x]!=x) return f[x]=Find(f[x]); return f[x]; } int main() { scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) { cin>>e[i].a>>e[i].b>>e[i].c; } sort(e+1,e+1+m,cmp); int sz=n,ans=0; for(int i=1;i<=m;i++) { int A=Find(e[i].a); int B=Find(e[i].b); if(A==B) continue; sz--; ans=ans+e[i].c; f[A]=B; } if(sz==1) printf("%d\n",ans); else printf("Impossible\n"); return 0; }
$15$.[分值:$30$] $5-19$ 两个有序序列的中位数
因为两个序列都是有序的,可以$O(n)$效率排序,但是他居然数据范围不是$100$万或者$1000$万,没有卡快排。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> #include<iostream> using namespace std; int n; int a[200010],b[100010]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=n+1;i<=n+n;i++) scanf("%d",&a[i]); sort(a+1,a+1+2*n); printf("%d\n",a[(2*n+1)/2]); return 0; }