2020.03.08【NOIP普及组】模拟赛C组14

题目编号标题
0反射(mirror)
1自动匹配(auto)
2道路阻塞(rblock)
3密码编码(scode)

T1:

题目描述

农夫约翰把他的很多镜子遗落在房子外面,他的奶牛们对这些镜子很好奇,于是奶牛们把这些镜子偷了!
奶牛们把镜子放在了一个N*M的矩阵中,在每个小方格中,他们将镜子按正对角线或者反对角线的方式放置,也就是说镜子的放置形状要么是’/’,要么是’\’。
某一天晚上,奶牛贝里斯拿着一个手电筒站在矩阵的外面,他打开手电筒按水平或者垂直方向朝矩阵内的镜子照射,由于镜子是对角线或者反对角线放置的,所以如果垂直的光过来的话,反射出来的光就是水平的,反之也是同样的道理。贝里斯想要知道他从外面照过来的光最多能被镜子反射几次。

输入

第一行是两个正整数N和M,表示矩阵的大小。
接下里N行,每行M个字符,表示矩阵内镜子放置的情况。字符是’/’或者’\’。

输出

输出一个整数,表示从外面照射进来的一束光最多能在矩阵内被反射的次数,如果会被反射无限次,就输出-1。

样例输入

 3 3 
 /\\ 
 \\\ 
 /\/
 

样例输出

3

数据范围限制

【数据规模】
1<=N,M<=1000。

提示

【样例说明】
贝里斯的光如果从中间列的上方照射的话,将被反射3次。

爆力即可,不用判断-1,应为死循环必须是个封闭空间,进都进不去。

#include<iostream>
#include<cstdio>
using namespace std;
int m,n,ans,maxx,f;
char a[2000][2000];
int main(){
	freopen("mirror.in","r",stdin);
	freopen("mirror.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)cin>>a[i][j];
	for(int i=1;i<=n;i+=n-1){
		for(int j=1;j<=m;j++){
			ans=0;
			int x=i,y=j;
			if(i==1)f=1;
			else f=3;
			while(1){
				ans++;
				if(a[x][y]=='/'&&f==1&&y>=1)y--,f=2;
				else
				if(a[x][y]=='/'&&f==2&&x<=n)x++,f=1;
				else
				if(a[x][y]=='/'&&f==3&&y<=m)y++,f=4;
				else
				if(a[x][y]=='/'&&f==4&&x>=1)x--,f=3;
				else
				if(a[x][y]!='/'&&f==1&&y<=m)y++,f=4;
				else
				if(a[x][y]!='/'&&f==2&&x>=1)x--,f=3;
				else
				if(a[x][y]!='/'&&f==3&&y>=1)y--,f=2;
				else
				if(a[x][y]!='/'&&f==4&&x<=m)x++,f=1;
				else break;
				if(x<1||x>n||y<1||y>m)break;
			}
			if(ans>maxx)maxx=ans;
		}
	}
	for(int j=1;j<=m;j+=m-1){
		for(int i=1;i<=n;i++){
			ans=0;
			int x=i,y=j;
			if(j==1)f=4;
			else f=2;
			while(1){
				ans++;
				if(a[x][y]=='/'&&f==1&&y>=1)y--,f=2;
				else
				if(a[x][y]=='/'&&f==2&&x<=n)x++,f=1;
				else
				if(a[x][y]=='/'&&f==3&&y<=m)y++,f=4;
				else
				if(a[x][y]=='/'&&f==4&&x>=1)x--,f=3;
				else
				if(a[x][y]!='/'&&f==1&&y<=m)y++,f=4;
				else
				if(a[x][y]!='/'&&f==2&&x>=1)x--,f=3;
				else
				if(a[x][y]!='/'&&f==3&&y>=1)y--,f=2;
				else
				if(a[x][y]!='/'&&f==4&&x<=m)x++,f=1;
				else break;
				if(x<1||x>n||y<1||y>m)break;
			}
			if(ans>maxx)maxx=ans;
		}
	}
	cout<<maxx;
	return 0;
}

T2:

题目描述

奶牛贝里斯最近有了一部新手机,于是他经常发短信。但是他经常打错单词,因为手机屏幕太小而他的爪子太大了((⊙o⊙))。农夫约翰决定帮助贝里	斯来开发一个app应用,使得可以从一个不完整的单词猜想整个单词。	
App应用是由W个单词组成的,每个单词都是由’a’..’z’组成的,这些单词总的长度不超过1000000。现在,总共有N个不完整的单词,每个单词的度不超过1000。对于第i个不完整的单词S_i,app应用要计算出在单词库中,按字典序排列的第K_i个前缀是S_i的单词。注意,自己也是自己的前缀。

输入

第一行是两个正整数W和N。
接下来W行,每行一个字典库里的单词。
接下里N行,每行一个K_i和其对应的不完整的单词S_i。

输出

输出包括N行,对于第i行,输出在字典库中按字典序排列的满足前缀是S_i的第K_i个单词在原字典库中的位置。如果没有足够的单词,就输出-1。

样例输入

10 3 
dab 
ba 
ab 
daa 
aa 
aaa 
aab 
abc 
ac 
dadba 
4 a 
2 da 
4 da

样例输出

3
1
-1

数据范围限制

【数据规模】
字典库中单词的总长度不超过1000000,1<=N<=1000,每个不完整的单词的长度不超过1000。
W<=30000

提示

【样例说明】
前缀是a的单词有aa,aaa,aab,ab,abc,ac,第4个是ab,ab在原字典库中是第3个。前缀是da的单词有daa,dab,dadba,第2个是dab,在原字典库中是第1个。没有第4个前缀是da的单词,所以输出-1。

一个一个找肯定会超时
那就用二分

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
using namespace std;
int m,n,k;
struct node{
	string st;
	int f;
}s[30005];
bool cmp(node x,node y){
	return x.st<y.st;
}
int main(){
	freopen("auto.in","r",stdin);
	freopen("auto.out","w",stdout);
	cin>>m>>n;
	for(int i=1;i<=m;i++){
		cin>>s[i].st;
		s[i].f=i;
	}
	sort(s+1,s+1+m,cmp);
	for(int i=1;i<=n;i++){
		string ss;
		int x;
		cin>>x>>ss;
		k=0;
		int l=1,r=m,mid,ans=-1;
		while(l<r){
			mid=(l+r)/2;
	        if(s[mid].st>=ss)r=mid;
	        else l=mid+1;
		}
		r=r+x-1;
		if(r>m){cout<<-1<<endl;continue;}
		bool flag=0;
		for(int j=0;j<ss.size();j++){
			if(s[r].st[j]!=ss[j]){
				flag=1;
				break;
			}
		}
		if(flag==0){
			cout<<s[r].f;
			cout<<endl;
		}
		else cout<<-1<<endl;
	}
	return 0;
}

T3:

题目描述

每天早上,约翰都要从他的家里步行去农场,他途中可能要经过其他的一些地方。我们把这些地方和路抽象成一张图,这张图里有N个点,共有M条边(每条边都是双向边),每条边都有一个长度,约翰的家在第1个点,农场在第N个点,两个点之间没有重复的边,并且这个图是一个连通图,每次约翰从家里到农场总会选一条最短的路径走。
但是约翰的奶牛们老是给约翰捣乱,奶牛们计划在其中某条路上放一些干草堆来阻碍约翰的行走,干草堆放在哪条路上,那条边的长度就相当于增加了一倍。现在,奶牛们想要知道如何选择一条边放干草堆,才能使约翰从家里到农场花费的路程增加最多。 

输入

第一行是两个正整数N和	M。
接下来M行,每行三个整数a,b,c表示点a到点b的距离是c。

输出

输出从家里到农场的最短路径最多会增加的距离。 

样例输入

5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2

样例输出

2

数据范围限制

【数据规模】
1<=N<=250,1<=M<=25000。

提示

【样例说明】	
当奶牛们把干草堆放在3-4的边上时,3-4的边的长度相当于从3变到6,约翰的最短路径就变成了1-3-5,总共的距离等于1+7=8,比原来的最短路长度增加了2。

SPFA

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int m,n,k,x[25555],y[25555],a[255][255];
int f[1001000],dis[255],v[255],be,en;
int spfa(){
	memset(dis,1,sizeof(dis));
	memset(v,0,sizeof(v));
	dis[1]=0;
	v[1]=1;
	f[1]=1;
	int head=0,tail=1;
	while(head<=tail){
		head++;
		int x1=f[head];
		for(int i=1;i<=n;i++){
			if(a[x1][i]!=0&&dis[i]>dis[x1]+a[x1][i]){
				dis[i]=dis[x1]+a[x1][i];
				if(v[i]!=1){
					v[i]=1;
					tail++;
					f[tail]=i;
				}
			}
		}
		v[x1]=0;
	}
	return dis[n];
}
int main(){
	freopen("rblock.in","r",stdin);
	freopen("rblock.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i]>>k;
		a[x[i]][y[i]]=k;
		a[y[i]][x[i]]=k;
	}
	be=spfa();
	for(int i=1;i<=m;i++){
		a[x[i]][y[i]]*=2;
		a[y[i]][x[i]]*=2;
		en=max(spfa()-be,en);
		a[x[i]][y[i]]/=2;
		a[y[i]][x[i]]/=2;
	}
	cout<<en;
	return 0;
}

T4:

题目描述

农夫约翰最近想发一些秘密的信息,但是他不想让奶牛们知道。这些信息是‘A’到’Z’的字符组成的,长度至少是2。
为了对这些信息进行加密,农夫约翰对这些信息进行了一系列的操作,每次操作,约翰把字符串S去掉从第一个开始连续的若干个字符或者从最后一个字符开始连续若干个字符(至少去掉一个字符,也不能全部去掉),然后把剩余的字符串添加到原来S串的左边或者右边。例如,对于字符串ABC,一次操作可以有8种结果:
AABC
ABABC
BCABC
CABC
ABCA
ABCAB
ABCBC
ABCC    
现在给定最后加密好的字符串,约翰想要知道这个字符串可能由多少种方法加密而来,注意,AAA可以由AA通过四种加密操作得来,虽然产生的AAA是一样的,但是加密的过程是不一样的我们就认为是不同的方法。

输入

一个字符串。

输出

输出这个加密的字符串可以由多少种方法加密而来。【答案要mod 2014】

样例输入

ABABA

样例输出

8

数据范围限制

【数据规模】
字符串的长度不超过100。 

提示

【样例说明】
我们有8种方法可以得到ABABA:
1. Start with ABA -> AB+ABA
2. Start with ABA -> ABA+BA
3. Start with AB -> AB+A -> AB+ABA
4. Start with AB -> AB+A -> ABA+BA
5. Start with BA -> A+BA -> AB+ABA
6. Start with BA -> A+BA -> ABA+BA
7. Start with ABAB -> ABAB+A
8. Start with BABA -> A+BABA

爆力DFS,加上hash判断

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
using namespace std;
int m,n,k,x,y;
map<string,int>a;
string s;
int dfs(string s){
	int sum=0,k=s.size();
	if(a.count(s))return a[s];
	for(int i=0;(i+1)*2<s.size();i++){
		if(s.substr(0,i+1)==s.substr(i+1,i+1)){
			sum+=dfs(s.substr(i+1,k-i-1));
		}
		if(s.substr(0,i+1)==s.substr(k-i-1,i+1)){
			sum+=dfs(s.substr(i+1,k-i-1));
		}
		if(s.substr(k-i-1,i+1)==s.substr(0,i+1)){
			sum+=dfs(s.substr(0,k-i-1));
		}
		if(s.substr(k-i-1,i+1)==s.substr(k-i*2-2,i+1)){
			sum+=dfs(s.substr(0,k-i-1));
		}
	}
	if(s.size()>=2)sum++;
	sum%=2014;
	a.insert(make_pair(s,sum));
	return sum;
}
int main(){
	freopen("scode.in","r",stdin);
	freopen("scode.out","w",stdout);
	cin>>s;
	cout<<dfs(s)-1;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值