纪中集训 Day25&Day26

纪中集训 Day25&Day26

当时没睡醒
又是历史最低分


T1

反射(mirror)

题目
农夫约翰把他的很多镜子遗落在房子外面,他的奶牛们对这些镜子很好奇,于是奶牛们把这些镜子偷了!
奶牛们把镜子放在了一个 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

自动匹配(auto)

题目
奶牛贝里斯最近有了一部新手机,于是他经常发短信。但是他经常打错单词,因为手机屏幕太小而他的爪子太大了((⊙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

道路阻塞(rblock)

题目
每天早上,约翰都要从他的家里步行去农场,他途中可能要经过其他的一些地方。我们把这些地方和路抽象成一张图,这张图里有 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值