赞
踩
打完决赛本菜鸡可以退役辣!并不是很开心因为上学期的考试还没复习完,哭了TAT
由于PTA还没有上架题目,只能描述个大概,各位姥爷见谅
给定一串时间序列,表示在什么时刻按了开关。在按下之后的15秒后会变绿灯,持续30秒,如果在持续期间有再次被按下则延长15秒,只能被延长一次,请输出所有的绿灯时间段
这第一题是真的恶心,我写它就写了快半个小时,蚌埠住了
大致思路就是模拟,如果灯没被按就变一下flag,然后维护一下st和ed两个时间段,如果这中间又被按了一下就ed+15这样子
#include<bits/stdc++.h> using namespace std; const int N=1010; int n; int a[N]; int main() { cin>>n; for (int i=1;i<=n;i++) cin>>a[i]; a[n+1]=0x3f3f3f3f; //让最后一个一定大于ed 防止特判 bool flag=false,add=false; //false代表没被按 true代表被按了 int st=0,ed=0; for (int i=1;i<=n+1;i++) { if (!flag) //没被按 { flag=true; st=a[i]+15;ed=a[i]+15+30-1; } else { if (a[i]<st) continue; if (a[i]>ed) { flag=false;add=false; cout<<st<<" "<<ed<<endl; i--;continue; } if (!add) { add=true; ed+=15; } } } return 0; }
给定一个5*5的棋盘,给定一个终点,有四只小怪,分别在棋盘的上下左右四个边界处,处于r1、r2、c1、c2四个行/列,还给定这四只小怪移动的距离,你要做的操作如下:
- 找到一个起始点
- 东西方向的小怪移动他们的距离,然后四只小怪一起攻击,攻击方式为小怪所在的本行/本列
- 你从起始点移动d1距离到第二个点
- 南北方向的小怪移动他们的距离,然后四只小怪一起攻击
- 你从第二个点移动d2距离到终点
要求每次移动到的点都不能被攻击,求合法的位置选择的具体方案
这题也是离了大谱,我看错题看错了两次,第一次以为移动的距离是只能往一个方向移动d1、d2的距离,第二次以为是小怪第一次不动,第二次东西南北一起动…他喵的
这个题可以反着推,从终点开始找,看看哪些点可以从终点走d2步到达,然后判断是否合法,再找哪些点可以从这个点走d1步到达且合法即可
不过问题是像俺这种解法是有可能重复的,由于unique函数不能用在结构体上(可能重载一下运算符可以,但我不会),所以写了个比较笨的去重,我感觉pair嵌套大礼包也是可以写的
#include<bits/stdc++.h> using namespace std; const int N=5; int c1,c2,r1,r2; int a[N]; int edx,edy,d1,d2; struct Node{ int a,b,c,d; friend bool operator<(Node x,Node y) { if (x.a!=y.a) return x.a<y.a; if (x.b!=y.b) return x.b<y.b; if (x.c!=y.c) return x.c<y.c; if (x.d!=y.d) return x.d<y.d; } }; int dx[]={1,1,-1,-1},dy[]={1,-1,1,-1}; bool equal(Node x,Node y) { if (x.a==y.a && x.b==y.b && x.c==y.c && x.d==y.d) return true; return false; } int main() { cin>>c1>>c2>>r1>>r2; for (int i=1;i<=4;i++) cin>>a[i]; cin>>edx>>edy>>d1>>d2; vector<Node> ans; for (int i=0;i<=d2;i++) { int dx1=i,dy1=d2-i; for (int k=0;k<4;k++) { int nx1=edx+dx1*dx[k],ny1=edy+dy1*dy[k]; if (nx1<1 || nx1>5 || ny1<1 || ny1>5) continue; if (nx1==r1-a[3] || nx1==r2+a[4] || ny1==c1+a[1] || ny1==c2-a[2]) continue; for (int j=0;j<=d1;j++) { int dx2=j,dy2=d1-j; for (int l=0;l<4;l++) { int nx2=nx1+dx2*dx[l],ny2=ny1+dy2*dy[l]; if (nx2<1 || nx2>5 || ny2<1 || ny2>5) continue; if (nx2==r1-a[3] || nx2==r2+a[4] || ny2==c1 || ny2==c2) continue; ans.push_back({nx2,ny2,nx1,ny1}); } } } } sort(ans.begin(),ans.end()); for (int i=0;i<ans.size();i++) if (!i || (i && !equal(ans[i],ans[i-1]))) cout<<ans[i].a<<" "<<ans[i].b<<" "<<ans[i].c<<" "<<ans[i].d<<endl; return 0; }
给定一个图有n个点,m条边,每条边的长度都为1,然后给定你起点S和终点T,同时给定你是在K个人中的第p个。给定所有点的权值,规定路径上的第1个点分给第1个人,第p个点分给第p个人,第p+1个点分给第1个人…问在保证路径最短的前提下,你最后能获得的最大权值和是多少?
这题乍一看像最短路,结果仔细想了一下重点在边长全为1上,那也就是说对于给定的起点和终点,中间如果存在两条路线可走,那么这两条路线上对应的点到起点的距离一定是相等的,那么这个问题其实就等价成了对于给定的起点和终点,途中第p+n*k(n>=0)中的点的权值之和最大是多少
那我们可以先bfs一遍求出来所有点的距离,然后再bfs一遍求出来价值之和即可
#include<bits/stdc++.h> using namespace std; const int N=100010,M=2*N; int n,m,k,p; int a[N]; int h[N],e[M],ne[M],idx; int S,T; int dist[N],val[N]; bool st[N]; void add(int a,int b) { e[idx]=b;ne[idx]=h[a];h[a]=idx++; } int main() { cin>>n>>m>>k>>p; for (int i=1;i<=n;i++) cin>>a[i]; memset(h,-1,sizeof(h)); while(m--) { int a,b;cin>>a>>b; add(a,b);add(b,a); } cin>>S>>T; memset(dist,0x3f,sizeof(dist)); queue<int> q; q.push(S); st[S]=true;dist[S]=1; while(!q.empty()) { int t=q.front();q.pop(); for (int i=h[t];~i;i=ne[i]) { int j=e[i]; if (dist[j]>dist[t]+1) { dist[j]=dist[t]+1; q.push(j); } } } memset(val,-0x3f,sizeof(val)); memset(st,0,sizeof(st)); q.push(S); st[S]=true;val[S]=0; while(!q.empty()) { int t=q.front();q.pop(); if (dist[t]>=p && (dist[t]-p)%k==0) { val[t]+=a[t]; } if (t==T) break; if (dist[t]>=dist[T]) continue; for (int i=h[t];~i;i=ne[i]) { int j=e[i]; if (dist[j]>dist[t] && val[j]<val[t]) val[j]=val[t]; if (!st[j]) { st[j]=true; q.push(j); } } } cout<<val[T]; return 0; }
需要注意的是,第二遍bfs我们一定要用dist[t]小于dist[T]的点去更新,因为其实是有可能出现dist[t]==dist[T],但是它先进入队列,并且和T有一条边,就把T的结果给更新了,然而这种是不合法的,因为这两个点距离相等,且和终点之间有一条边,那么从它走到T一定不是最短路径了
从下面的题开始我就开始瞎写了
题目大意是给定两个数组,问你最少需要多少步操作可以把数组一变成数组二,并且要求给出对第一个数组的操作:
- 如果当前数字不变,输出2
- 如果当前数字被删除,输出0
- 如果当前数字前或后被添加了一个数字,输出3
- 如果当前数字被改变,输出1
没什么好说,照着编辑距离瞎写的,结束2分钟交了一发举然骗到了17分,绝了
这题听说只管操作1和2打暴力能拿20分,tm比我凹了半天的解得分还高,我是真的会谢
#include<bits/stdc++.h> using namespace std; const int N=1010; int a[N],b[N]; int lena,lenb; int f[N][N]; string ans[N][N]; int main() { int t=0; while(t!=-1) { cin>>t; a[++lena]=t; } t=0; while(t!=-1) { cin>>t; b[++lenb]=t; } memset(f,0x3f,sizeof(f)); for (int i=0;i<=lena;i++) { f[i][0]=i; if (!i) ans[i][0]=""; else ans[i][0]=ans[i-1][0]+"3"; } for (int i=0;i<=lenb;i++) { f[0][i]=i; if (!i) ans[0][i]=""; else ans[0][i]=ans[0][i-1]+"3"; } for (int i=1;i<=lena;i++) for (int j=1;j<=lenb;j++) { f[i][j]=min(f[i][j],f[i-1][j]+1); if (a[i]==b[j]) f[i][j]=min(f[i][j],f[i-1][j-1]); else f[i][j]=min(f[i][j],f[i-1][j-1]+1); if (f[i][j]==f[i-1][j]+1) { if (i>j) ans[i][j]=ans[i-1][j]+"0"; else ans[i][j]=ans[i-1][j]+"3"; } else if (f[i][j]==f[i-1][j-1]) { ans[i][j]=ans[i-1][j-1]+"2"; } else if (f[i][j]==f[i-1][j-1]+1) { ans[i][j]=ans[i-1][j-1]+"1"; } } cout<<f[lena][lenb]<<endl; cout<<ans[lena][lenb]; return 0; }
给定一棵树,和所有点的种类,问你有多少个三元组,这三个点之间的最短距离两两相同,且这三个点的种类都不同
没什么好说,一点思路都没有,floyd嗯跑拿了17分,结束前20分钟的时候在想是不是可以floyd换bfs,后来一想后面枚举的部分不会优化,那总的时间复杂度还是O(n^3),没区别啊
结果赛后有人告诉我floyd换bfs直接拿满了,我当场怀疑人生
#include<bits/stdc++.h> using namespace std; const int N=2010; typedef pair<int,pair<int,int>> PIII; int n; int g[N][N]; int t[N]; int main() { cin>>n; memset(g,0x3f,sizeof(g)); for (int i=1;i<=n-1;i++) { int a,b;cin>>a>>b; g[a][b]=g[b][a]=1; } for (int i=1;i<=n;i++) cin>>t[i]; for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=min(g[i][j],g[i][k]+g[k][j]); vector<PIII> ans; for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=j+1;k<=n;k++) { if (g[i][j]==g[j][k] && g[i][j]==g[i][k]) { if (t[i]!=t[j] && t[i]!=t[k] && t[j]!=t[k]) { ans.push_back({i,{j,k}}); } } } cout<<ans.size(); return 0; }
总的来说还算凑合,因为只需要有分就能拿奖,打得很放松,最后交的一发也送我拿了国一(应该吧?),94分摸了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。