考前模拟冲刺2
Posted 一蓑烟雨任生平
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考前模拟冲刺2相关的知识,希望对你有一定的参考价值。
1. 足球联赛
(soccer.pas/c/cpp )
题目描述:
巴蜀中学新一季的足球联赛开幕了。足球联赛有 n只球队参赛,每赛季,每只球队要与其他球队各赛两场,主客各一场,赢一场得 3 分,输一场不得分,平局两只队伍各得一分。 英勇无畏的小鸿是机房的主力前锋,她总能在关键时刻踢出一些匪夷所思的妙球。但是很可惜,她过早的燃烧完了她的职业生涯,不过作为一个能够 Burning 的 girl,她的能力不止如此,她还能预测这个赛季所有球队的比赛结果。 虽然她能准确预测所有比赛的结果,但是其实她不怎么厉害,Mr.Gao 上数学课时她总是在 sleep,因此她的脑里只有整数没有实数,而且,她只会 10 以内非负整数的加法运算,因此她只有结果却无法知道谁会获得联赛的冠军。 小鸿想给冠军队伍的所有队员一个拥抱,所以她把计算结果的任务交给了你:现在,给你一个 n*n 的矩阵表示比赛情况。第 i 行第 j 列的字母表示在第 i 只队伍 在主场迎战第 j 只队伍的比赛情况,W 表示主队赢,L 表示主队输,D 表示平局。现在需要你给出最后能得到小鸿拥抱的队伍编号,如有多支队伍分数最高,按字典序输出编号。
输入格式:
第一行一个整数 n。
接下来 n 行,每行 n 个字符,表示输赢情况。第 i 行第 i 列为 - ,因为一只队伍不可能与自己比赛。
输出格式:
输出得分最高的队伍编号。如有多个在一行中输出,用一个空格分开。
样例输入:
样例1
3 -WW W-W WW-
样例2
5 -DWWD L-WLL DD-WD DDL-L DDLL-
样例输出:
样例1
123
样例2
1
数据范围:
对于 40%的数据,满足 N<=20 对于 100%的数据,满足 N<=50
思路:暴力即可,水题。但是没有注意胜利是加3分,所以gg了┭┮﹏┭┮,下次要细心啊!!
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n; char s[60]; struct nond{ int num,id; }v[60]; int cmp(nond a,nond b){ if(a.num==b.num) return a.id<b.id; return a.num>b.num; } int main(){ freopen("soccer.in","r",stdin); freopen("soccer.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s+1); v[i].id=i; for(int j=1;j<=n;j++){ if(s[j]==\'D\'){ v[i].num+=1;v[j].num+=1; } else if(s[j]==\'W\'){ v[i].num+=3; } else if(s[j]==\'L\'){ v[j].num+=3; } } } sort(v+1,v+1+n,cmp); for(int i=1;i<=n;i++) if(v[i].num==v[1].num) cout<<v[i].id<<" "; return 0; }
2. 最短路径
(paths.pas/c/cpp )
题目描述:
平面内给出 n 个点,记横坐标最小的点为 A,最大的点为 B,现在小 Y 想要知道在 每个点经过一次(A 点两次)的情况下从 A 走到 B,再回到 A 的最短路径。但他是个强 迫症患者,他有许多奇奇怪怪的要求与限制条件: 1.从 A 走到 B 时,只能由横坐标小的点走到大的点。 2.由 B 回到 A 时,只能由横坐标大的点走到小的点。 3.有两个特殊点 b1 和 b2, b1 在 0 到 n-1 的路上,b2 在 n-1 到 0 的路上。 请你帮他解决这个问题助他治疗吧!
输入格式:
第一行三个整数 n,b1,b2,( 0 < b1,b2 < n-1 且 b1 <> b2)。n 表示点数,从 0 到 n-1 编号,b1 和 b2 为两个特殊点的编号。 以下 n 行,每行两个整数 x、y 表示该点的坐标(0 <= x,y <= 2000),从 0 号点顺序给出。Doctor Gao 为了方便他的治疗,已经将给出的点按 x 增序排好了。
输出格式:
输出仅一行,即最短路径长度(精确到小数点后面 2 位)
样例输入:
5 1 3 1 3 3 4 4 1 7 5 8 3
样例输出:
18.18
样例解释:
最短路径:0->1->4->3->2->0
数据范围:
20%的数据 n<=20 60%的数据 n<=300 100%的数据 n<=1000 对于所有数据 x,y,b1,b2 如题目描述.
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 1001 using namespace std; int n,b1,b2; struct nond{ int x,y; }cnt[MAXN]; int vis[MAXN]; double bns,ans=0x7f7f7f7f; double dis[MAXN][MAXN]; void slove(){ int pre=1;bns=0; for(int i=pre+1;i<=n;i++) if(!vis[i]||i==n){ bns+=dis[pre][i]; pre=i; } } void dfs(double sum,int pre){ if(vis[b2]) return ; if(pre>b1&&!vis[b1]) return ; if(pre==n){ if(!vis[1]||!vis[b1]||vis[b2]==1||!vis[n]) return ; slove(); ans=min(sum+bns,ans); return ; } for(int i=pre+1;i<=n;i++) if(!vis[i]){ vis[i]=1; dfs(sum+dis[pre][i],i); vis[i]=0; } } int main(){ freopen("paths.in","r",stdin); freopen("paths.out","w",stdout); scanf("%d%d%d",&n,&b1,&b2);b1+=1;b2+=1; for(int i=1;i<=n;i++) scanf("%d%d",&cnt[i].x,&cnt[i].y); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) dis[i][j]=dis[j][i]=sqrt((cnt[i].x-cnt[j].x)*(cnt[i].x-cnt[j].x)+(cnt[i].y-cnt[j].y)*(cnt[i].y-cnt[j].y)); dfs(0,0); printf("%.2lf",ans); }
正解思路:动态规划
(定义dis[i][j]表示点i到点j之间的直线距离)
把问题简化 后可以发现,问题其实可以看成这样一个问题:平面上n个点,确定一条连接各点的最短闭合旅程,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。
然后不妨把问题中从n到1路线看成是从1到n的路线,这样我们就有了两条从1到n的路线。
定义f[i][j]表示从点i到点j的路径,理解为:从点i开始,从右到左一直到点1,然后从左到右一直到点j。在这个路径上,会经过点1到点max(i,j)之间的所有点且只经过一次。
可以列出状态转移方程为:
定义k为max(i,j)+1;
f[1][1]=0;
f[i][k]=min(f[i][k],f[i][j]+dis[j][k]);
f[k][j]=min(f[k][j],f[i][j]+dis[i][k]);
还要考虑一些特殊情况,比如:
点b1,b2。
还有k=max(i,j)+1;(i==n||j==n)的情况。
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 1001 using namespace std; int n,b1,b2; struct nond{ int x,y; }cnt[MAXN]; double dis[MAXN][MAXN],f[MAXN][MAXN]; int main(){ freopen("paths.in","r",stdin); freopen("paths.out","w",stdout); scanf("%d%d%d",&n,&b1,&b2);b1+=1;b2+=1; for(int i=1;i<=n;i++) scanf("%d%d",&cnt[i].x,&cnt[i].y); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=dis[j][i]=sqrt((cnt[i].x-cnt[j].x)*(cnt[i].x-cnt[j].x)+(cnt[i].y-cnt[j].y)*(cnt[i].y-cnt[j].y)); memset(f,0x7f,sizeof(f)); f[1][1]=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j||i==1){ int k=max(i,j)+1; if(k-1==n){ if(i!=n) f[n][n]=min(f[n][n],f[i][j]+dis[i][n]); if(j!=n) f[n][n]=min(f[n][n],f[i][j]+dis[j][n]); continue; } if(k!=b1) f[i][k]=min(f[i][k],f[i][j]+dis[j][k]); if(k!=b2) f[k][j]=min(f[k][j],f[i][j]+dis[i][k]); } printf("%.2lf",f[n][n]); }
3.阿 Q 的停车场
(park.pas/c/cpp )
题目描述:
刚拿到驾照的 KJ 总喜欢开着车到处兜风,玩完了再把车停到阿 Q 的停车场里,虽然她对自己停车的水平很有信心,但她还是不放心其他人的停车水平,尤其是 Kelukin。
于是,她每次都把自己的爱车停在距离其它车最远的一个车位。KJ 觉得自己这样的策略非常科学,于是她开始想:在一个停车场中有一排车位,从左到右编号为 1 到 n,初始时全部是空的。
有若干汽车,进出停车场共 m 次。对于每辆进入停车场的汽车,会选择与其它车距离最小值最大的一个车位,若有多个符合条件,选择最左边一个。
KJ 想着想着就睡着了,在她一旁的 Kelukin 想帮她完成这个心愿,但是他又非常的懒,不愿意自己动手,于是就把这个问题就留给了你:
在 KJ 理想的阿 Q 的停车场中,给你车辆进出的操作序列,依次输出每辆车的车位编号。
输入格式:
第一行,两个整数 n 和 m,表示停车场大小和操作数; 接下来 m 行,每行两个整数 F 和 x F 是 1 表示编号为 x 的车进停车场; F 是 2 表示编号为 x 的车出停车场; 保证操作合法,即: 出停车场的车一定目前仍在停车场里; 停车场内的车不会超过 n;
输出格式:
对于所有操作 1,输出一个整数,表示该车车位的编号。
样例输入:
7 11 1 15 1 123123 1 3 1 5 2 123123 2 15 1 21 2 3 1 6 1 7 1 8
样例输出:
1 7 4 2 7 4 1 3
数据范围:
对 30%的数据 n<=1000 ,m<=1000 对 60%的数据 n<=200000,m<=2000 对 100%的数据 n,m<=200000,车的编号小于等于 10^6
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 200010 using namespace std; map<int,int>ma; int n,m,tot; int vis[MAXN],stop[MAXN]; struct nond{ int now,l,r; int len,ren,sum; int ll,rr,sum1,sum2; }tree[MAXN*4]; void up(int now){ // if(tree[now*2].l==1) if(tree[now*2].sum>=tree[now*2+1].sum) tree[now].sum=tree[now*2].sum,tree[now].sum1=tree[now*2].sum1,tree[now].sum2=tree[now*2].sum2; else tree[now].sum=tree[now*2+1].sum,tree[now].sum1=tree[now*2+1].sum1,tree[now].sum2=tree[now*2+1].sum2; if(tree[now*2].ren+tree[now*2+1].len>tree[now].sum) tree[now].sum=tree[now*2].ren+tree[now*2+1].len,tree[now].sum1=tree[now*2].rr,tree[now].sum2=tree[now*2+1].ll; else if(tree[now*2].ren+tree[now*2+1].len==tree[now].sum) if(tree[now*2].rr<tree[now].sum1&&tree[now*2].rr!=0) tree[now].sum1=tree[now*2].rr,tree[now].sum2=tree[now*2+1].ll; tree[now].len=tree[now*2].len; tree[now].ll=tree[now*2].ll; tree[now].ren=tree[now*2+1].ren; tree[now].rr=tree[now*2+1].rr; if(tree[now].ll>=tree[now].sum1&&tree[now].sum2>=tree[now].rr){ tree[now].sum=tree[now].len=tree[now].ren=tree[now].r-tree[now].l+1; tree[now].ll=tree[now].sum2=tree[now].r; tree[now].rr=tree[now].sum1=tree[now].l; } else if(tree[now].ll>=tree[now].sum1){ tree[now].sum=tree[now].len=tree[now].sum2-tree[now].l+1; tree[now].sum1=tree[now].l; tree[now].ll=tree[now].sum2; } else if(tree[now].sum2>=tree[now].rr){ tree[now].sum=tree[now].ren=tree[now].r-tree[now].sum1+1; tree[now].sum2=tree[now].r; tree[now].rr=tree[now].sum1; } } void build(int now,int l,int r){ tree[now].l=l; tree[now].r=r; if(tree[now].l==tree[now].r){ tree[now].len=1; tree[now].ren=1; tree[now].sum=1; tree[now].ll=tree[now].r; tree[now].rr=tree[now].l; tree[now].sum1=tree[now].l; tree[now].sum2=tree[now].r; return ; } int mid=(tree[now].l+tree[now].r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); up(now); } void change(int now,int x,int k){ if(tree[now].l==tree[now].r){ if(k==1){ tree[now].ll=0; tree[now].rr=0; tree[now].sum1=0; tree[now].sum2=0; tree[now].sum=0; tree[now].len=0; tree[now].ren=0; } if(k==0){ tree[now].sum=1; tree[now].len=1; tree[now].ren=1; tree[now].ll=tree[now].r; tree[now].rr=tree[now].l; tree[now].sum1=tree[now].l; tree[now].sum2=tree[now].r; } return ; } int mid=(tree[now].l+tree[now].r)/2; if(x<=mid) change(now*2,x,k); else if(x>mid) change(now*2+1,x,k); up(now); } int main(){ freopen("park.in","r",stdin); freopen("park.out","w",stdout); scanf("%d%d",&n,&m); if(n<=1000&&m<=1000){ for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if(x==1){ ma[y]=++tot; int len=0,pos,maxn=-1,l; for(int j=1;j<=n;j++){ if(!vis[j]) len++; else{ if(len==0) continue; if(j-len==1){ maxn=len-1;l=len;pos=1; } else{ int k=(len-1)/2; if(k>maxn){ maxn=k;l=len;pos=j-len; } } len=0; } } if((len-1)/2>maxn){ maxn=(len-1)/2;l=len;pos=n-len+1; } int last=pos+l-1,mid=(pos+last)/2; if(pos==1) vis[pos]=1,stop[tot]=pos,cout<<pos<<endl; else if(last==n) vis[last]=1,stop[tot]=last,cout<<last<<endl; else if(pos!=1&&last!=n) vis[mid]=1,stop[tot]=mid,cout<<mid<<endl; } if(x==2) vis[stop[ma[y]]]=0; } } else if(n<=200000&&m<=2000){ build(1,1,n); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); if(x==1){ ma[y]=++tot; int len=0,pos=0; if(tree[1].len) len=tree[1].len,pos=1; if(tree[1].ren>len) len=tree[1].ren,pos=tree[1].r; if((tree[1].sum-1)/2>len) len=tree[1].sum,pos=(tree[1].sum2-tree[1].sum1)/2; change(1,pos,1); stop[tot]=pos; cout<<pos<<endl; } else change(1,stop[ma[y]],0); } } }
/* 维护的区间中间最长的 区间从左边开始向右能拓展到的最长的。 区间从右边开始向左能拓展到的最长的。 然后没有调出来处理。 */ #include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 200010 using namespace std; map<int,int>ma; int n,m,tot; int vis[MAXN],stop[MAXN]; struct nond{ int now,l,r; int len,ren,sum; int ll,rr,sum1,sum2; }tree[MAXN*4]; void up(int now){ if(tree[now*2].sum>=tree[now*2+1].sum) tree[now].sum=tree[now*2].sum,tree[now].sum1=tree[now*2].sum1,tree[now].sum2=tree[now*2].sum2; else tree[now].sum=tree[now*2+1].sum,tree[now].sum1=tree[now*2+1].sum1,tree[now].sum2=tree[now*2+1].sum2; if(tree[now*2].ren+tree[now*2+1].len>tree[now].sum) tree[now].sum=tree[now*2].ren+tree[now*2+1].len,tree[now].sum1=tree[now*2].rr,tree[now].sum2=tree[now*2+1].ll; else if(tree[now*2].ren+tree[now*2+1].len==tree[now].sum) if(tree[now*2].rr<tree[now].sum1&&tree[now*2].rr!=0) tree[now].sum1=tree[now*2].rr,tree[now].sum2=tree[now*2+1].ll; tree[now].len=tree[now*2].len; tree[now].ll=tree[now*2].ll; tree[now].ren=tree[now*2+1].ren; tree[now].rr=tree[now*2+1].rr; if(tree[now].ll>=tree[now].sum1&&tree[now].sum2>=tree[now].rr&&tree[now].ll!=0&&tree[now].rr!=0){ tree[now].sum=tree[now].len=tree[now].ren=tree[now].r-tree[now].l+1; tree[now].ll=tree[now].sum2=tree[now].r; tree[now].rr=tree[now].sum1=tree[now].l; } else if(tree[now].ll>=tree[now].sum1&&tree[now].sum1!=0&&tree[now].ll!=0){ tree[now].sum=tree[now].len=tree[now].sum2-tree[now].l+1; tree[now].sum1=tree[now].l; tree[now].ll=tree[now].sum2; } else if(tree[now].sum2>=tree[now].rr&&tree[now].rr!=0&&tree[now].sum2!=0){ tree[now].sum=tree[now].ren=tree[now].r-tree[now].sum1+1; tree[now].sum2=tree[now].r; tree[now].rr=tree[now].sum1; } } void build(int now,int l,int r){ tree[now].l=l; tree[now].r=r; if(tree[now].l==tree[now].r){ tree[now].len=1; tree[now].ren=1; tree[now].sum=1; tree[now].ll=tree[now].r; tree[now].rr=tree[now].l; tree[now].sum1=tree[now].l; tree[now].sum2=tree[now].r; return ; } int mid=(tree[now].l+tree[now].r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); up(now); } void change(int now,int x,int k){ if(tree[now].l==tree[now].r){ if(k==1){ tree[now].ll=0; tree[now].rr=0; tree[now].sum1=0; tree[now].sum2=0; tree[now].sum=0; tree[now].len=0; tree[now].ren=0; } if(k==0){ tree[now].sum=1; tree[now].len=考前冲刺 14.19免费公开课-软考·网络工程师考前30天冲刺提分策略解读