2019天梯赛L1及L2全解
题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/type/7?page=0
基础级:L1-057~064
进阶级:L2-029~032
登顶级:L3-022~024
题目说明:
前七题:水题,字符串,
估值一亿的AI核心代码(大模拟)
特立独行的幸福(暴力模拟) 冰岛人(暴力|LCA)
深入虎穴(最长路) 彩虹瓶(水题-模拟)
emmmm,怀念当年我还是大一的时候啊,现在的我已经是个混吃等死的死宅了QAQ,总的来说当年这套题似乎也不是很难,我这种蒟蒻学了半年也能写个110+的分数。。。想当时写完我还自闭了好久,拖了队伍的后退啊QAQ。。。
基础级:
总的来说没什么难的,当然除了最后一题。。。。最后一题调太久了而且最终还没出来,要是当时直接扔了也不至于分数这么低,前面的七题大概半个小时就差不多了。
PTA使我精神焕发(5)
没什么好说的,直接printf就完事了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int main() { printf ("PTA shi3 wo3 jing1 shen2 huan4 fa1 !\n"); return 0; }
6翻了(15)
没什么好说的,就是不能用gets,那么只能换getline并用string来解决了,我们for一遍直接处理就好了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=1e3+10; string s; int main() { getline(cin,s); int len=s.length(); for (int i=0; i<len; i++){ if (s[i]=='6'){ int j,mis=0; for (j=i; j<len; j++){ if (s[j]!='6') break; mis++; } i=j; if (mis<=3) for (int k=1; k<=mis; k++) printf("6"); else if (mis>3 && mis<=9) printf("9"); else printf("27"); } printf("%c",s[i]); } printf("\n"); return 0; }
敲笨钟(20)
也没什么好说的,读一句处理一句就好了,至于怎么处理,直接暴力来就完事了,值得注意的一点是读入整数过后要用getchar将回车吃掉,不然第一个字符串就是回车符了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; string s; int main() { int n; scanf ("%d",&n); getchar(); for (int i=1; i<=n; i++){ getline(cin,s); int len=s.length()-1; int mid,mark=0; for (int j=0; j<=len; j++) if (s[j]==',') mid=j; if (s[mid-1]=='g' && s[mid-2]=='n' && s[mid-3]=='o') if (s[len-1]=='g' && s[len-2]=='n' && s[len-3]=='o'){ mark=1; int pos,space=0; for (int j=len; j>mid; j--){ if (s[j]==' ') space++; if (space==3) {pos=j;break;} } for (int j=0; j<=pos; j++) printf("%c",s[j]); printf("qiao ben zhong.\n"); } if (!mark) printf("Skipped\n"); } return 0; }
心理阴影面积(5)
没什么好说的,就是一个大三角形减去小三角形再减去一个梯形就完事了,值得注意的是这里的面积运算都要使用int型,最后的结果也是int型
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int main() { int x,y; int tot=100*100/2; scanf ("%d%d",&x,&y); int s1=(100-x)*(100-y)/2; int s2=(100+100-x)*y/2; printf("%d\n",tot-s1-s2); return 0; }
新胖子公式(10)
emmmm,没什么好说的了,不要加上精度误差就能过
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int main() { double weight,heigt; cin>>weight>>heigt; double ans=(weight/(heigt*heigt)); printf("%.1f\n",ans); if (ans>25) printf("PANG\n"); else printf("Hai Xing\n"); return 0; }
幸运彩票(15)
这个也很简单,直接看代码
以下是AC代码:
#include <bits/stdc++.h> using namespace std; char s[10]; int solve(char c1,char c2,char c3) { int p1=c1-'0',p2=c2-'0',p3=c3-'0'; return p1+p2+p3; } int main() { int n; scanf ("%d",&n); for (int i=1; i<=n; i++){ scanf ("%s",s); int s1=solve(s[0],s[1],s[2]); int s2=solve(s[3],s[4],s[5]); if (s1==s2) printf("You are lucky!\n"); else printf("Wish you good luck.\n"); } return 0; }
吃鱼还是吃肉(10)
没什么好说的,if-else判断即可,复制粘贴别出错就行了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int main() { int n; scanf ("%d",&n); for (int i=1; i<=n; i++){ int sx,height,weight; scanf ("%d%d%d",&sx,&height,&weight); if (sx==1){ if (height>130) printf("ni li hai! "); else if (height==130) printf("wan mei! "); else printf("duo chi yu! "); if (weight>27) printf("shao chi rou!\n"); else if (weight==27) printf("wan mei!\n"); else printf("duo chi rou!\n"); } else { if (height>129) printf("ni li hai! "); else if (height==129) printf("wan mei! "); else printf("duo chi yu! "); if (weight>25) printf("shao chi rou!\n"); else if (weight==25) printf("wan mei!\n"); else printf("duo chi rou!\n"); } } return 0; }
估值一亿的AI核心代码(20)
emmmm,当时记得调了很久,现在看来。。。也不是很难,我们先做最简单的替换,也就是将大写变小写(除了I),将“?”变成“!”,接下来我们必须先解决多余的空格问题,这个也不是很难,我们先搞定头尾,这个就很简单了,那么得出的新的头尾设为head和tail。然后我们从head到tail直接for一遍一旦碰到非空格的我们就一直往下读,遇到空格,我们要进行一个简单的判断,先往下读,读到非空格,判断这个字符是不是数字和字母,(标点符号非常多,难以判断),如果是的话我们就直接在新的字符串中添加一个空格,如果不是的话我们直接break:
string ss; int head=0,tail=len-1; while (s[head]==' ') head++;//空格消除 while (s[tail]==' ') tail--; for (int i=head; i<=tail; i++) { int j; if (letter(s[i]) || number(s[i])) { for (j=i; j<=tail; j++) { if (!letter(s[j]) && !number(s[j])) break; ss+=s[j]; } i=j-1; } else if (s[i]==' ') { for (j=i; j<=tail; j++) { if (letter(s[j]) || number(s[j])) { ss+=' '; break; } else if (s[j]!=' ') break; } i=j-1; } else ss+=s[i]; }
这样得到的ss就是一个比较完美的无多余空格的字符串,那么现在我们就只剩下替换I,me,can you,could you了,当然我们如果直接替换的话会有一定的难度,所以我们可以换一种方法思考,我们可以对要替换的单词进行标记然后就没了。标记过程如下:
int lens=ss.length(); for (int i=0; i<lens; i++) { //标记I,me,can you,could you的位置 if (ss[i]=='I') { if (i==0 && !letter(ss[i+1]) && !number(ss[i+1])) id[i]=1; else if (ss[i-1]==' ' && !letter(ss[i+1]) && !number(ss[i+1])) id[i]=1; } else if (ss[i]=='m' && ss[i+1]=='e') { if (i==0 && !letter(ss[i+2]) && !number(ss[i+2])) id[i]=2; else if (ss[i-1]==' ' && !letter(ss[i+2]) && !number(ss[i+2])) id[i]=2; } else if (can(ss,i)) id[i]=3; else if (could(ss,i)) id[i]=4; }
那么接下来就是编写letter,number,can,could这4个判断函数了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; string s; int id[1010]; //1--表示I,2--表示me,3表示can you,4表示could you char cny[]={'c','a','n',' ','y','o','u'}; char cdy[]={'c','o','u','l','d',' ','y','o','u'}; int letter(char c)//判断字母 { if (c>='a' && c<='z') return 1; if (c>='A' && c<='Z') return 1; return 0; } int number(char c)//判断数字 { if (c>='0' && c<='9') return 1; return 0; } int can(string ss,int st)//判断是否为独立的can you { if (st==0){ for (int i=0; i<7; i++) if (ss[i+st]!=cny[i]) return 0; if (letter(ss[st+7]) || number(ss[st+7])) return 0; } else { if (ss[st-1]!=' ') return 0; for (int i=0; i<7; i++) if (ss[i+st]!=cny[i]) return 0; if (letter(ss[st+7]) || number(ss[st+7])) return 0; } return 1; } int could(string ss,int st)//判断是否为独立的could you { if (st==0){ for (int i=0; i<9; i++) if (ss[i+st]!=cdy[i]) return 0; if (letter(ss[st+9]) || number(ss[st+9])) return 0; } else { if (ss[st-1]!=' ') return 0; for (int i=0; i<9; i++) if (ss[i+st]!=cdy[i]) return 0; if (letter(ss[st+9]) || number(ss[st+9])) return 0; } return 1; } int main() { int n; scanf ("%d",&n); getchar(); while(n--){ getline(cin,s); cout<<s<<endl; cout<<"AI: "; memset(id,0,sizeof id); int len=s.length(); for (int i=0; i<len; i++){//简单替换 if (letter(s[i])) if (s[i]<'a' && s[i]!='I') s[i]+=32; if (s[i]=='?') s[i]='!'; } string ss; int head=0,tail=len-1; while (s[head]==' ') head++;//空格消除 while (s[tail]==' ') tail--; for (int i=head; i<=tail; i++){ int j; if (letter(s[i]) || number(s[i])){ for (j=i; j<=tail; j++){ if (!letter(s[j]) && !number(s[j])) break; ss+=s[j]; } i=j-1; } else if (s[i]==' '){ for (j=i; j<=tail; j++){ if (letter(s[j]) || number(s[j])) {ss+=' '; break;} else if (s[j]!=' ') break; } i=j-1; } else ss+=s[i]; } //得到的ss无多余空格 int lens=ss.length(); for (int i=0; i<lens; i++){//标记I,me,can you,could you的位置 if (ss[i]=='I'){ if (i==0 && !letter(ss[i+1]) && !number(ss[i+1])) id[i]=1; else if (ss[i-1]==' ' && !letter(ss[i+1]) && !number(ss[i+1])) id[i]=1; } else if (ss[i]=='m' && ss[i+1]=='e'){ if (i==0 && !letter(ss[i+2]) && !number(ss[i+2])) id[i]=2; else if (ss[i-1]==' ' && !letter(ss[i+2]) && !number(ss[i+2])) id[i]=2; } else if (can(ss,i)) id[i]=3; else if (could(ss,i)) id[i]=4; } for (int i=0; i<lens; i++){ if (!id[i]) cout<<ss[i]; else if (id[i]==1) cout<<"you"; else if (id[i]==2) {cout<<"you"; i++;} else if (id[i]==3) { cout<<"I can"; i+=6; } else if (id[i]==4){ cout<<"I could"; i+=8; } } cout<<endl; } return 0; }
进阶级:
emmm,也基本都是水题,除了冰岛人有点恶心人。。。我想当初我要是扔掉大模拟那题那得加多少分啊QAQ!!!
特立独行的幸福(25)
emmm,乍一看还有点蒙,不过按照他的要求来的话也不是很难,就是感觉有点难的样子。。。。我们直接暴力就可以了,在区间内寻找,然后在寻找的过程中进行标记,对于已经标记过的点就直接扔了,也是挺简单的一题
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=1e4+10; int prim[mac],vis[mac],num[mac]; bool mk[mac]; int solve(int m) { int tot=0; while (m){ int p=m%10; tot+=p*p; m/=10; } return tot; } int ok(int s,int m) { memset(mk,false,sizeof mk); mk[m]=true; while (m!=1){ m=solve(m); if (mk[m]) return -1; mk[m]=true;vis[m]=1; s++; } return s-1; } int main() { int l,r; int p=sqrt(mac); for (int i=2; i<=p; i++) if (!prim[i]) for (int j=i*i; j<=mac; j+=i) prim[j]=1; scanf ("%d%d",&l,&r); for (int i=l; i<=r; i++){ if (vis[i]) continue; num[i]=ok(1,i); } int yes=0; for (int i=l; i<=r; i++){ if (vis[i]) continue; if (num[i]<1) continue; if (!prim[i]) yes=1,printf ("%d %d\n",i,num[i]*2); else yes=1,printf ("%d %d\n",i,num[i]); } if (!yes) printf ("SAD\n"); return 0; }
冰岛人(25)
首先,看题目。。。。真的看了很久。。。看不懂QAQ,所谓的其他人不知道指的是什么,题目说保证维京人的起源都是男性m,那么f是个什么鬼?直接当场去世。。。。所谓的五代以内也有点疑惑
好吧,题目还是要做的。。。。硬着头皮肝了一下,既然说起源都是男性m,那么f应该没什么用了吧,扔掉后跑了一遍。。。19分,加上f,把她当祖宗另加一个if-else判断末尾。。。23分,原来过了测试点的没过,我。。。。
然后我就想了想,只改变性别试试,至于她的姓可以和m的一样,这样就可以最大限度地保持原来代码的模样,结果一下子就过了。。。。真是蜜汁WA
不过本题的数据感觉有点水。。。本来想用LCA的,结果直接暴力都可以过,这里先将其中一个点的所有父亲都找出来,并打上标记,附上到每个点的距离。然后跑另一个点就完事了。
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=1e5+10; struct node { string ming,xing; int sx;//0女,1男 }name[mac]; int fa[mac]; unordered_map<string,int>q1,q2; int same(string s1,string s2,int id1,int id2) { unordered_map<int,int>dis,vis; dis[id1]=1;vis[id1]=1; int p=1; while(fa[id1]!=-1){ id1=fa[id1]; dis[id1]=++p; vis[id1]=1; if (id1==id2) return 0; } p=1; while (fa[id2]!=-1){ id2=fa[id2]; ++p; if (vis[id2]){ if (dis[id2]>4 && p>4) return 1; else return 0; } } return 1; } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n; cin>>n; memset(fa,-1,sizeof fa); for (int i=1; i<=n; i++){ string s1,s2; cin>>s1>>s2; q1[s1]=i; int len2=s2.length(); if (s2[len2-1]=='n'){ name[i].sx=1; name[i].ming=s1; name[i].xing=s2.substr(0,len2-4); } else if (s2[len2-1]=='r'){ name[i].sx=0; name[i].ming=s1; name[i].xing=s2.substr(0,len2-7); } else { name[i].ming=s1; if (s2[len2-1]=='m') name[i].sx=1; else name[i].sx=0; name[i].xing="m"; } } for (int i=1; i<=n; i++){ if (name[i].xing=="m") continue; fa[i]=q1[name[i].xing]; if (!fa[i]) fa[i]=-1; } int m; cin>>m; while (m--){ string ming1,xing1,ming2,xing2; cin>>ming1>>xing1>>ming2>>xing2; if (!q1[ming1] || !q1[ming2]){ cout<<"NA"<<endl; continue; } if (name[q1[ming1]].sx==name[q1[ming2]].sx){ cout<<"Whatever"<<endl; continue; } if (same(ming1,ming2,q1[ming1],q1[ming2])){ cout<<"Yes"<<endl; continue; } cout<<"No"<<endl; } return 0; }
深入虎穴(25)
emmmm,看起来不是很难,确实也不是很难,就是坑了点,首先就是入口不知道(我刚开始一直以为是1)QAQ,实际上是没有入度的点,接下来就是他有一个n=1的数据。。。。那么最短距离就是0。。。我在这两个地方栽了一回。实际上就是跑个dij改编的最长路就完事了。
以下是AC代码:
#include <bits/stdc++.h> using namespace std; const int mac=1e5+10; struct node { int to,w,next; }eg[mac<<2]; struct way { int id,s; bool operator <(const way&a)const{ return s<a.s; } }; int head[mac],num=0,dis[mac],vis[mac],n; int fa[mac]; void add(int u,int v) { eg[++num]=node{v,1,head[u]}; head[u]=num; } void dij(int id) { priority_queue<way>q; q.push(way{id,0}); while (!q.empty()){ way now=q.top(); q.pop(); int u=now.id; for (int i=head[u]; i!=-1; i=eg[i].next){ int v=eg[i].to; if (dis[u]+eg[i].w>dis[v]) { dis[v]=dis[u]+eg[i].w; q.push(way{v,dis[v]}); } } } int mx=-1,mxid; for (int i=1; i<=n; i++) if (dis[i]>mx) mx=dis[i],mxid=i; printf("%d\n",mxid); } int main() { scanf ("%d",&n); memset(head,-1,sizeof head); for (int i=1; i<=n; i++){ int m; scanf ("%d",&m); for (int j=1; j<=m; j++){ int v; scanf ("%d",&v); fa[v]=i; add(i,v); } } for (int i=1; i<=n; i++) if (!fa[i]){ dij(i);break; } return 0; }
彩虹瓶(25)
emmm,像这种没有罚时的情况下我们可以写个随机数去多跑几遍,至于得几分那就看命了QAQ
先看题目。。。。有点长,看完之后觉得。。。太简单了!写一发。。。。确实简单,用个简单的栈模拟一下过程跑一跑就完事了
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int id[1010],sstack[1010]; int main() { int n,m,s; scanf ("%d%d%d",&n,&m,&s); while (s--){ for (int i=1; i<=n; i++) scanf ("%d",&id[i]); int tail=0,use=1,mark=0; for (int i=1; i<=n; i++){ if (id[i]==use) use++; else { while (tail && sstack[tail-1]==use) {use++; tail--;} if (id[i]==use) {use++; continue;} sstack[tail++]=id[i]; if (tail>m) {mark=1; printf("NO\n"); break;} } } while (tail && sstack[tail-1]==use) {use++; tail--;} if (!mark & !tail) printf("YES\n"); else if (!mark) printf("NO\n"); } return 0; }
登顶级:
emmm。。。。有点懒了,下次一定记得补
地铁一日游
计算图
Oriol和David