第二周双周赛和week7

一、输出全排列

在这里插入图片描述

2.样例

输入

3

输出

123
132
213
231
312
321

3.思路

用dfs,将每种情况存储,遍历一个数后标记一下,后面取消标记。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n;
int a[11];
bool vis[11];
void dfs(int t){
	if(t==n+1){
	for(int i=1;i<=n;i++){
		cout<<a[i];
	}
	cout<<endl;
	return ;	
	}
	for(int j=1;j<=n;j++){
	if(!vis[j]){
	a[t]=j;
	vis[j]=1;	
	dfs(t+1);
	vis[j]=0;
	}
	}
} 
int main() {
	cin>>n;
	dfs(1);
	return 0;
}

二、山

1.题目

在这里插入图片描述

2.样例

输入

4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

输出

3

3.思路

如果这个点是山,向四周遍历,如果四周没山则是高山。如果四周有山则以有山的点向四周遍历,经过的点需要标记。

4.代码

#include<bits/stdc++.h>
using namespace std;
int m,n,sum;
int a[2100][2100];
bool vis[2100][2100];
int b1[4]={-1,1,0,0};
int b2[4]={0,0,-1,1};
void f(int i,int j,int c){
	vis[i][j]=1;
	if(a[i][j]==0) return ;
	int sum1=1;
	for(int k=0;k<4;k++){
		sum1+=a[i+b1[k]][j+b2[k]];
		if(a[i+b1[k]][j+b2[k]]==1&&!vis[i+b1[k]][j+b2[k]]){
			f(i+b1[k],j+b2[k],1);
		}
	}
	if(sum1==1&&c==0) sum++;
	else if(sum1>1&&c==0) sum++;
}
int main(){
	cin>>m>>n;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			int x;cin>>x;
			a[i][j]=x;
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(!vis[i][j]){
			f(i,j,0);	
			}
		}
	}
	cout<<sum;
}

三、跳跃

1.题目

在这里插入图片描述

2.样例

输入

7
4 2 3 0 3 1 2
5

输出

True

3.思路

bfs的运用。注意两点一个是出口不是0点,是下标为0的点;二是从0点开始,不能从1点开始存储。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n,start;
int m[510000];
bool vis[510000];
queue<int>q;
int main() {
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>m[i];
	}
	cin>>start;
	q.push(start);
	vis[start]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		if(m[x]==0){
			cout<<"True";
			return 0;
		}
		if(x+m[x]<n&&!vis[x+m[x]])
			q.push(x+m[x]),vis[x+m[x]]=1;
		if(x-m[x]>=0&&!vis[x-m[x]])
		q.push(x-m[x]),vis[x-m[x]]=1;
	}
	cout<<"False";
	return 0;
}

四、最长光路

1.题目

在这里插入图片描述

2.样例

输入

5 7
/.....\
../..\.
\...../
/.....\
\.\.../
3 3

输出

R
COOL

3.思路

从光源开始分别向上下左右遍历,找出最大的路径。判断方向的改变需要细心些。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n,m,sx,sy,ans;
char a[501][501];
bool vis[501][501][4];
char d[4]={'U','R','D','L'};
char dans;
int len;
int maxn=0x7f7f7f7f;
void dfs(int x,int y,int dir){
	if(vis[x][y][dir]){
		len=maxn;
		return ;
	}
	len++;
	vis[x][y][dir]=1;
	if(a[x][y]=='\\'){
		if(dir==0){
			dir=3;
			y--;
		}else if(dir==1){
			dir=2;
			x++;
		}else if(dir==2){
			dir=1;
			y++;
		}else if(dir==3){
			dir=0;
			x--;
		}
	}else if(a[x][y]=='/'){
		if(dir==0){
			dir=1;
			y++;
		}else if(dir==1){
			dir=0;
			x--;
		}else if(dir==2){
			dir=3;
			y--;
		}else if(dir==3){
			dir=2;
			x++;
		}
	}else{
		if(dir==0){
			x--;
		}else if(dir==1){
			y++;
		}else if(dir==2){
			x++;
		}else if(dir==3){
			y--;
		}
	}
	if(x<1||x>n||y<1||y>m||a[x][y]=='C') return ;
	dfs(x,y,dir);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j]; 
		}
	}
	cin>>sx>>sy;
	for(int i=0;i<4;i++){
		memset(vis,0,sizeof(vis));
		len=0;
		dfs(sx,sy,i);
		if(len>ans) dans=d[i],ans=len;
	}
	cout<<dans<<endl;
	if(ans==maxn) cout<<"COOL";
	else cout<<ans;
	return 0;
}

五、回文数文回

1.题目

在这里插入图片描述

2.样例

输入

100000001

输出

1

3.思路

先将前5个点列举出来,后面四个点分别与前面四个点保持一致,不大于n的点都是回文数。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n,ans; 
int main(){
	cin>>n;
	for(int i1=1;i1<=9;i1++){
		for(int i2=0;i2<=9;i2++){
			for(int i3=0;i3<=9;i3++){
				for(int i4=0;i4<=9;i4++){
					for(int i5=0;i5<=9;i5++){
						int sum=i1*1e8+i2*1e7+i3*1e6+i4*1e5+i5*1e4+i4*1e3+i3*1e2+i2*10+i1;
						if(sum<=n) ans++;
					}
				}
			}
		}
	}
	cout<<ans;
}

week7

[NOIP2005 普及组] 采药

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 2 2 2 个整数 T T T 1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000)和 M M M 1 ≤ M ≤ 100 1 \le M \le 100 1M100),用一个空格隔开, T T T 代表总共能够用来采药的时间, M M M 代表山洞里的草药的数目。

接下来的 M M M 行每行包括两个在 1 1 1 100 100 100 之间(包括 1 1 1 100 100 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

样例 #1

样例输入 #1

70 3
71 100
69 1
1 2

样例输出 #1

3

提示

【数据范围】

  • 对于 30 % 30\% 30% 的数据, M ≤ 10 M \le 10 M10
  • 对于全部的数据, M ≤ 100 M \le 100 M100

【题目来源】

NOIP 2005 普及组第三题

3.思路

如果时间不够用直接进行下一个循环,够用时ans[i][j]=max(ans[i-1][j],ans[i-1][j-t[i]]+v[i]);最后结果为ans[M][T]。

4.代码

#include<bits/stdc++.h>
using namespace std;
int T,M;
int  t[1100],v[1100];
int ans[1100][1100];
int main(){
	cin>>T>>M;
	for(int i=1;i<=M;i++)
	cin>>t[i]>>v[i];
	memset(ans[0],0,sizeof(ans[0]));
	for(int i=1;i<=M;i++){
		for(int j=0;j<=T;j++){
			if(j<t[i])
			ans[i][j]=ans[i-1][j];
			else
			ans[i][j]=max(ans[i-1][j],ans[i-1][j-t[i]]+v[i]);
		}
	}
	cout<<ans[M][T];
}

最长上升子序列

题目描述

这是一个简单的动规板子题。

给出一个由 n ( n ≤ 5000 ) n(n\le 5000) n(n5000) 个不超过 1 0 6 10^6 106 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。

最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。

输入格式

第一行,一个整数 n n n,表示序列长度。

第二行有 n n n 个整数,表示这个序列。

输出格式

一个整数表示答案。

样例 #1

样例输入 #1

6
1 2 4 1 3 4

样例输出 #1

4

提示

分别取出 1 1 1 2 2 2 3 3 3 4 4 4 即可。

3.思路

暴力搜索,从第一个开始向前寻找比其小的数,如果比前面的大ans[i]=max(ans[i],1+ans[j]),最后找到ans[]当中最大的数。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n;
int a[5001],ans[5001];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++)
	ans[i]=1;
	for(int i=1;i<=n;i++){
		for(int j=i-1;j>=1;j--){
			if(a[i]>a[j]){
				ans[i]=max(ans[i],1+ans[j]);
			}
		}
	}
	int mx=1;
	for(int i=1;i<=n;i++)
	mx=max(mx,ans[i]);
	cout<<mx;
}

最大子段和

题目描述

给出一个长度为 n n n 的序列 a a a,选出其中连续且非空的一段使得这段和最大。

输入格式

第一行是一个整数,表示序列的长度 n n n

第二行有 n n n 个整数,第 i i i 个整数表示序列的第 i i i 个数字 a i a_i ai

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

7
2 -4 3 -1 2 -4 3

样例输出 #1

4

提示

样例 1 解释

选取 [ 3 , 5 ] [3, 5] [3,5] 子段 { 3 , − 1 , 2 } \{3, -1, 2\} {3,1,2},其和为 4 4 4

数据规模与约定
  • 对于 40 % 40\% 40% 的数据,保证 n ≤ 2 × 1 0 3 n \leq 2 \times 10^3 n2×103
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105 − 1 0 4 ≤ a i ≤ 1 0 4 -10^4 \leq a_i \leq 10^4 104ai104

3.思路

如果这个数加上前面的数和比自己小,则这个ans[i]=这个数,比自己大则ans[i]=ans[i-1]+a[i];最后再找出他们当中的最大和。

4.代码

#include<bits/stdc++.h>
using namespace std;
int n,mx;
int a[500001];
int ans[500001];
int main(){
	cin>>n;
	mx=INT_MIN;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++){
		ans[i]=max(a[i],ans[i-1]+a[i]);
		mx=max(mx,ans[i]);
	}
	cout<<mx;
}

LCS

题面翻译

题目描述:

给定一个字符串 s s s 和一个字符串 t t t ,输出 s s s t t t 的最长公共子序列。

输入格式:

两行,第一行输入 s s s ,第二行输入 t t t

输出格式:

输出 s s s t t t 的最长公共子序列。如果有多种答案,输出任何一个都可以。

说明/提示:

数据保证 s s s t t t 仅含英文小写字母,并且 s s s t t t 的长度小于等于3000。

题目描述

文字列 $ s $ および $ t $ が与えられます。 $ s $ の部分列かつ $ t $ の部分列であるような文字列のうち、最長のものをひとつ求めてください。

输入格式

入力は以下の形式で標準入力から与えられる。

$ s $ $ t $

输出格式

$ s $ の部分列かつ $ t $ の部分列であるような文字列のうち、最長のものをひとつ出力せよ。 答えが複数ある場合、どれを出力してもよい。

样例 #1

样例输入 #1

axyb
abyxb

样例输出 #1

axb

样例 #2

样例输入 #2

aa
xayaz

样例输出 #2

aa

样例 #3

样例输入 #3

a
z

样例输出 #3


样例 #4

样例输入 #4

abracadabra
avadakedavra

样例输出 #4

aaadara

提示

注釈

文字列 $ x $ の部分列とは、$ x $ から $ 0 $ 個以上の文字を取り除いた後、残りの文字を元の順序で連結して得られる文字列のことです。

制約

  • $ s $ および $ t $ は英小文字からなる文字列である。
  • $ 1\ \leq\ |s|,\ |t|\ \leq\ 3000 $

Sample Explanation 1

答えは axb または ayb です。 どちらを出力しても正解となります。

Sample Explanation 3

答えは `` (空文字列) です。

4.代码

#include<bits/stdc++.h>
using namespace std;
int dp[5000][5000];
char a[10001],b[10001],ans[10001];
int main(){
	int i,j;
    scanf("%s%s",a+1,b+1);
	for(i=1;i<=strlen(a+1);i++){
		for(j=1;j<=strlen(b+1);j++){
			dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			if(a[i]==b[j])
            dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
		}
	}
	i--,j--;
	while(dp[i][j]>0){
		if(a[i]==b[j]){
            ans[dp[i][j]]=a[i];
            i--, j--;
        }
		else{
			if(dp[i][j]==dp[i-1][j]) i--;
			else j--;
		}
	}
	cout<<ans+1;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木易·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值