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>20分的暴力
#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>10分的暴力
#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=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);
}
}
#include<cstdio>std
#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;
}