纪中集训 Day25&Day26
当时没睡醒
又是历史最低分
T1
题目:
农夫约翰把他的很多镜子遗落在房子外面,他的奶牛们对这些镜子很好奇,于是奶牛们把这些镜子偷了!
奶牛们把镜子放在了一个
N
N
N*
M
M
M的矩阵中,在每个小方格中,他们将镜子按正对角线或者反对角线的方式放置,也就是说镜子的放置形状要么是’/’,要么是’\’。
某一天晚上,奶牛贝里斯拿着一个手电筒站在矩阵的外面,他打开手电筒按水平或者垂直方向朝矩阵内的镜子照射,由于镜子是对角线或者反对角线放置的,所以如果垂直的光过来的话,反射出来的光就是水平的,反之也是同样的道理。贝里斯想要知道他从外面照过来的光最多能被镜子反射几次。
输入:
第一行是两个正整数
N
N
N和
M
M
M,表示矩阵的大小。
接下里
N
N
N行,每行
M
M
M个字符,表示矩阵内镜子放置的情况。字符是’/’或者’\’。
输出;
输出一个整数,表示从外面照射进来的一束光最多能在矩阵内被反射的次数,如果会被反射无限次,就输出-1。
样例:
input
3 3
/\\
\\\
/\/
output
3
数据范围限制:
1<=
N
4
,
N4,
N4,M$<=1000。
提示:
贝里斯的光如果从中间列的上方照射的话,将被反射3次。
解题思路:
暴力,有8个方向反射
代码:
#include<iostream>
#include<cstdio>
using namespace std;
char a[1001][1001];
int n,m,x,y,ans;
void mj(int x1,int y1,int f)
{
int ma=1;
while (1==1)
{
if (a[x1][y1]=='/'&&f==1&&y1>1)
{
y1--,f=4,ma++;
continue;
}
if (a[x1][y1]=='/'&&f==2&&x1>1)
{
x1--,f=3,ma++;
continue;
}
if (a[x1][y1]=='/'&&f==3&&y1<m)
{
y1++,f=2,ma++;
continue;
}
if (a[x1][y1]=='/'&&f==4&&x1<n)
{
x1++,f=1,ma++;
continue;
}
if (a[x1][y1]!='/'&&f==1&&y1<m)
{
y1++,f=2,ma++;
continue;
}
if (a[x1][y1]!='/'&&f==2&&x1<n)
{
x1++,f=1,ma++;
continue;
}
if (a[x1][y1]!='/'&&f==3&&y1>1)
{
y1--,f=4,ma++;
continue;
}
if (a[x1][y1]!='/'&&f==4&&x1>1)
{
x1--,f=3,ma++;
continue;
}
break;
}
ans=max(ma,ans);
}
int main()
{
freopen("mirror.in","r",stdin);
freopen("mirror.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>a[i][j];
x=1;
for (y=1;y<=m;y++) //从上面射
mj(x,y,1);
x=n;
for (y=1;y<=m;y++) //从下面射
mj(x,y,3);
y=1;
for (x=1;x<=n;x++) //从左面射
mj(x,y,2);
y=m;
for (x=1;x<=n;x++) //从右面射
mj(x,y,4);
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
T2
题目:
奶牛贝里斯最近有了一部新手机,于是他经常发短信。但是他经常打错单词,因为手机屏幕太小而他的爪子太大了((⊙o⊙))。农夫约翰决定帮助贝里斯来开发一个
a
p
p
app
app应用,使得可以从一个不完整的单词猜想整个单词。
A
p
p
App
App应用是由
W
W
W个单词组成的,每个单词都是由’
a
a
a’…’
z
z
z’组成的,这些单词总的长度不超过1000000。现在,总共有
N
N
N个不完整的单词,每个单词的度不超过1000。对于第i个不完整的单词
S
S
S
i
i
i,
a
p
p
app
app应用要计算出在单词库中,按字典序排列的第
K
K
K
i
i
i个前缀是
S
S
S_
i
i
i的单词。注意,自己也是自己的前缀。
输入:
第一行是两个正整数
W
W
W和
N
N
N。
接下来
W
W
W行,每行一个字典库里的单词。
接下里
N
N
N行,每行一个
K
K
K
i
i
i和其对应的不完整的单词
S
S
S
i
i
i。
输出:
输出包括N行,对于第i行,输出在字典库中按字典序排列的满足前缀是S_i的第K_i个单词在原字典库中的位置。如果没有足够的单词,就输出-1。
样例:
input:
10 3
dab
ba
ab
daa
aa
aaa
aab
abc
ac
dadba
4 a
2 da
4 da
output:
3
1
-1
数据范围限制;
字典库中单词的总长度不超过1000000,1<=
N
N
N<=1000,每个不完整的单词的长度不超过1000。
W
W
W<=30000
提示;
前缀是
a
a
a的单词有
a
a
aa
aa,
a
a
a
aaa
aaa,
a
a
b
aab
aab,
a
b
ab
ab,
a
b
c
abc
abc,
a
c
ac
ac,第4个是
a
b
ab
ab,
a
b
ab
ab在原字典库中是第3个。前缀是
d
a
da
da的单词有
d
a
a
daa
daa,
d
a
b
dab
dab,
d
a
d
b
a
dadba
dadba,第2个是
d
a
b
dab
dab,在原字典库中是第1个。没有第4个前缀是
d
a
da
da的单词,所以输出-1。
解题思路:
先食用一下lower_bound
然后就ok了
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct hhx{
int x;
string s;
}a[35010];
int n,m,y,z,l,r,mid,len;
string c,x,f[35010];
bool cmp(hhx t,hhx x)
{
return (t.s<x.s);
}
int main()
{
freopen("auto.in","r",stdin);
freopen("auto.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
cin>>a[i].s;
a[i].x=i;
}
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++)
f[i]=a[i].s;
for (int i=1;i<=m;i++)
{
cin>>y>>x;
int k=lower_bound(f+1,f+n+1,x)-f; //找到第一次出现的位置
if (f[k+y-1].find(x,0)==0) //用find查找,如果出现在第一位,就是前缀
cout<<a[k+y-1].x<<endl;
else cout<<"-1"<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
T3
题目:
每天早上,约翰都要从他的家里步行去农场,他途中可能要经过其他的一些地方。我们把这些地方和路抽象成一张图,这张图里有
N
N
N个点,共有
M
M
M条边(每条边都是双向边),每条边都有一个长度,约翰的家在第1个点,农场在第
N
N
N个点,两个点之间没有重复的边,并且这个图是一个连通图,每次约翰从家里到农场总会选一条最短的路径走。
但是约翰的奶牛们老是给约翰捣乱,奶牛们计划在其中某条路上放一些干草堆来阻碍约翰的行走,干草堆放在哪条路上,那条边的长度就相当于增加了一倍。现在,奶牛们想要知道如何选择一条边放干草堆,才能使约翰从家里到农场花费的路程增加最多。
输入:
第一行是两个正整数
N
N
N和
M
M
M。
接下来
M
M
M行,每行三个整数
a
a
a,
b
b
b,
c
c
c表示点
a
a
a到点
b
b
b的距离是
c
c
c。
输出:
输出从家里到农场的最短路径最多会增加的距离。
样例:
input
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
output
2
数据范围限制:
1<=
N
N
N<=250,1<=
M
M
M<=25000。
提示:
当奶牛们把干草堆放在3-4的边上时,3-4的边的长度相当于从3变到6,约翰的最短路径就变成了1-3-5,总共的距离等于1+7=8,比原来的最短路长度增加了2。
解题思路:
一次BFS找最短路
然后暴力枚举每条边乘2,再做一次
B
F
S
BFS
BFS
找出最长的一条
然后和最短的相减
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct hhx{
int q,to,next;
}m2[25010];
struct yty{
int d,m;
}c[260];
int d[260],f[260],p[260],head[260];
int n,m,l,r,x,y,z,t;
void add(int x,int y,int z)
{
m2[++t].q=z;
m2[t].to=y;
m2[t].next=head[x];
head[x]=t;
}
void spfa1()
{
memset(d,0x7f,sizeof(d));
memset(p,0,sizeof(p));
memset(c,0,sizeof(c));
int h=0,t=1;
f[1]=1;
p[1]=1;
d[1]=0;
do{
h++;
for (int i=head[f[h]];i;i=m2[i].next)
if (d[f[h]]+m2[i].q<d[m2[i].to])
{
d[m2[i].to]=d[f[h]]+m2[i].q;
c[m2[i].to].d=f[h];
c[m2[i].to].m=i;
if (p[m2[i].to]==0)
{
f[++t]=m2[i].to;
p[m2[i].to]=1;
}
}
p[f[h]]=0;
}while(h<t);
}
void spfa2()
{
memset(d,0x7f,sizeof(d));
memset(p,0,sizeof(p));
int h=0,t=1;
f[1]=1;
p[1]=1;
d[1]=0;
do{
h++;
for (int i=head[f[h]];i;i=m2[i].next)
if (d[f[h]]+m2[i].q<d[m2[i].to])
{
d[m2[i].to]=d[f[h]]+m2[i].q;
if (p[m2[i].to]==0)
{
f[++t]=m2[i].to;
p[m2[i].to]=1;
}
}
p[f[h]]=0;
}while(h<t);
}
int main()
{
freopen("rblock.in","r",stdin);
freopen("rblock.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
spfa1(); //第一次找最短路
l=d[n];
r=l;
int k=n;
while (k>0)
{
x=c[k].m;
m2[x].q*=2; //边乘2
spfa2(); //再一次BFS
r=max(d[n],r); //找最长路
m2[x].q/=2; //复原
k=c[k].d; //找下一条
}
cout<<r-l<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}