考前模拟冲刺2

时间:2021-04-17 15:49:58

考前模拟冲刺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-10 的路上。
请你帮他解决这个问题助他治疗吧!

输入格式:

 第一行三个整数 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 如题目描述.

 

考前模拟冲刺2考前模拟冲刺2
#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);
}
20分的暴力

正解思路:动态规划

(定义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

 

考前模拟冲刺2考前模拟冲刺2
#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);
}
}
}
10分的暴力
考前模拟冲刺2考前模拟冲刺2
/*
维护的区间中间最长的
区间从左边开始向右能拓展到的最长的。
区间从右边开始向左能拓展到的最长的。
然后没有调出来处理。
*/
#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
=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);
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,flag=0;
if(tree[1].len) len=tree[1].len-1,pos=1,flag=1;
if(tree[1].ren-1>len) len=tree[1].ren-1,pos=tree[1].r,flag=1;
if((tree[1].sum-1)/2>len) len=tree[1].sum,pos=(tree[1].sum2+tree[1].sum1)/2;
else if((tree[1].sum-1)/2==len&&!flag) len=tree[1].len,pos=(tree[1].sum1+tree[1].sum2)/2;
change(
1,pos,1);
stop[tot]
=pos;
cout
<<pos<<endl;
}
else change(1,stop[ma[y]],0);
}
}
没调出来的线段树
考前模拟冲刺2考前模拟冲刺2
#include<cstdio>
#include
<iostream>
#include
<cstring>

using namespace std;

const int N=200002;
struct node{
int x,y,mid,p;
};
node tree[N
<<4];
int n,m;
int car[1000001]; //车的位置,如果你6可以加离散化啊

void update(int bh)
{
int lc=bh<<1;
int rc=(bh<<1)+1;
if (bh)
{
tree[bh].x
=tree[lc].x;
tree[bh].y
=tree[rc].y;
tree[bh].mid
=tree[lc].mid;
tree[bh].p
=tree[lc].p;
if (tree[rc].mid>tree[bh].mid)
{
tree[bh].mid
=tree[rc].mid; tree[bh].p=tree[rc].p;
}
int l=tree[rc].y-tree[lc].x+1; //两个区间之间的空位
if (l>tree[bh].mid)
{
tree[bh].mid
=l;
tree[bh].p
=(tree[lc].y+tree[rc].x)>>1;
}
}
return;
}

void add(int bh,int l,int r,int wz,int z)
{
if (l==wz&&l==r)
{
if (z==1)
{
tree[bh].x
=l;
tree[bh].y
=r;
tree[bh].mid
=0; //节点上有车了,当然就没有mid和p值了
tree[bh].p=0;
return;
}
else
{
tree[bh].x
=0;
tree[bh].y
=0;
tree[bh].mid
=0;
tree[bh].p
=0;
return;
}

}
int mid=(l+r)>>1;
if (wz<=mid) add(bh<<1,l,mid,wz,z);
if (wz>mid) add((bh<<1)+1,mid+1,r,wz,z);
update(bh);
}

int main()
{
scanf(
"%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int opt,u;
scanf(
"%d%d",&opt,&u);
if (opt==1)
{
if (tree[1].x==0) //整颗线段树的信息都集中在根节点
{
car[u]
=1; //整个停车场都是空的
}
else
{
int mx=-1;
if (tree[1].x-1>mx)
{
mx
=tree[1].x-1;
car[u]
=1; //第一个车位没人停
}
if (tree[1].mid>mx)
{
mx
=tree[1].mid;
car[u]
=tree[1].p;
}
if (n-tree[1].y>mx)
{
//最后的车位没人停
mx=n-tree[1].y;
car[u]
=n;
}
}
printf(
"%d\n",car[u]);
add(
1,1,n,1,1);
}
else
{
add(
1,1,n,car[u],-1); //出停车场
}
}
return 0;
}
std