洛谷习题3

本文介绍了NOIP 2016提高组的玩具谜题解题思路,涉及玩具小人的位置变化和方向理解。随后讨论了如何通过递归和记忆化搜索解决Function问题,以及如何通过贪心算法处理线段覆盖问题。机器翻译部分展示了如何根据内存限制和指令顺序合理安排单词存储。最后,一道关于走方格的动态规划问题,探讨了从起点到终点的路径规划。
摘要由CSDN通过智能技术生成


P1563 [NOIP2016 提高组] 玩具谜题

题目描述
小南有一套可爱的玩具小人, 它们各有不同的职业。
有一天, 这些玩具小人把小南的眼镜藏了起来。 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图:
这时singersinger告诉小南一个谜題: “眼镜藏在我左数第3个玩具小人的右数第11个玩具小人的左数第22个玩具小人那里。 ”

小南发现, 这个谜题中玩具小人的朝向非常关键, 因为朝内和朝外的玩具小人的左右方向是相反的: 面朝圈内的玩具小人, 它的左边是顺时针方向, 右边是逆时针方向; 而面向圈外的玩具小人, 它的左边是逆时针方向, 右边是顺时针方向。

有 n个玩具小人围成一圈, 已知它们的职业和朝向。现在第1个玩具小人告诉小南一个包含m条指令的谜題, 其中第 z条指令形如“左数/右数s个玩具小人”。 你需要输出依次数完这些指令后,到达的玩具小人的职业。

输入格式
输入的第一行包含两个正整数 n,m,表示玩具小人的个数和指令的条数。

接下来 n 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 0 表示朝向圈内,1 表示朝向圈外。 保证不会出现其他的数。字符串长度不超过 10 且仅由小写字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。

接下来 m 行,其中第 ii 行包含两个整数 a_i,s_i,表示第i 条指令。若 a_i=0,表示向左数 s_i个人;
若 a_i=1,表示向右数 s_i个人。
输出格式
输出一个字符串,表示从第一个读入的小人开始,依次数完 mm 条指令后到达的小人的职业。

输入输出样例
输入 #1复制
7 3
0 singer
0 reader
0 mengbier
1 thinker
1 archer
0 writer
1 mogician
0 3
1 1
0 2
输出 #1复制
writer

package 洛谷习题;

import java.util.Scanner;

public class P1563 {
	static int m,n;
	static int a[] = new int [101000];
	static String s[] = new String [101000];
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		m = in.nextInt();
		n = in.nextInt();
		for(int i=1;i<=m;i++) {
			a[i] = in.nextInt();
			s[i] = in.next();
		}
		int index = 1;
		for(int i=0;i<n;i++)
		{
			int a1 = in.nextInt();
			int b1= in.nextInt();
			
			//退
			if(a1==0&&a[index]==0) {
				index -=b1;
				if(index<1) {
					  index = -index;
					  index = index%m;
					  index = m-index;
				}
				}	
			else if(a1==1&&a[index]==1) {
				index -=b1;
				if(index<1) {
					  index = -index;
					  index = index%m;
					  index = m-index;

				}
			}
			
			
			//进
			else if(a1==1&&a[index]==1) {
				index +=b1;
				if(index>m)
					index = index%m;
				}
		    else{
				index +=b1;
				if(index>m)
					index = index%m;
				}
			}
				
		System.out.println(s[index]);
	}
		}

P1464 Function

在这里插入图片描述
解题思路:单纯递归肯定会超时,所以需要增加记忆化搜索,因为最大也就20,所以我们可以开一个三维数组,存放不同a,b,c时的值,并且设置一个布尔类型的数组,在递归的时候判断是否为真,如果是说明算过了,直接返回已经算过的数值。

package 洛谷习题;

import java.util.Scanner;

public class P1464 {
	static int w(int a,int b,int c) {
		if(a<=0 || b<=0 || c<=0)return 1;
		else if(a>20 || b>20 || c>20)
			return w(20,20,20);
		if(v[a][b][c]) return k[a][b][c];
		else if(a<b&&b<c)
			k[a][b][c] =  w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
		else
			k[a][b][c] =  w((a-1),b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
		v[a][b][c] = true;
		return k[a][b][c];
	}
	
	static int k[][][] = new int [21][21][21];
	static boolean v[][][] = new boolean [21][21][21];

	public static void main(String[] args) {
		Scanner in = new Scanner (System.in);
		boolean flag = true;
		while(flag) {
			int a1 = in.nextInt();
			int b1 = in.nextInt();
			int c1 = in.nextInt();
			if(a1==-1&&b1==-1&&c1==-1)
				flag = false;
			else {
				int ans = w(a1,b1,c1);
				System.out.printf("w(%d, %d, %d) = %d\n",a1,b1,c1,ans);
			}
		}
	}
}

P1803 凌乱的yyy / 线段覆盖

题目描述
现在各大 oj 上有 n 个比赛,每个比赛的开始、结束的时间点是知道的。

y 认为,参加越多的比赛,noip 就能考的越好(假的)。

所以,他想知道他最多能参加几个比赛。

由于 y 是蒟蒻,如果要参加一个比赛必须善始善终,而且不能同时参加 2 个及以上的比赛。

输入格式
第一行是一个整数 n ,接下来 n 行每行是 2 个整数 a_{i},b_{i}( a_{i}<b_{i} ),表示比赛开始、结束的时间。

输出格式
一个整数最多参加的比赛数目。

输入输出样例
输入 #1复制
3
0 2
2 4
1 3
输出 #1复制
2
解题思路:贪心先对数组按结束时间进行排序,然后从第一个开始往后遍历,如果上一个的结束时间小于下一个的开始时间,则计数器加一,同时标记新的结束时间与下一个对比。


import java.util.Arrays;
import java.util.Scanner;

public class P1803 {
	static int n,ans,ens;
	static class Game implements Comparable<Game>{
		int start;
		int end;
		public Game(int start, int end) {
			super();
			this.start = start;
			this.end = end;
		}
		 
		public int compareTo(Game o) {
			return this.end - o.end;
		}
	}
	static Game[] game = new Game[1000000];
	public static void main(String[] args) {
		Scanner in = new Scanner (System.in);
		n = in.nextInt();
		for(int i=0;i<n;i++) {
			int a = in.nextInt();
			int b = in.nextInt();
			game[i]  = new Game(a, b);
		}
		
		Arrays.sort(game,0,n);
		
		int startTime = game[0].start;  第一个肯定有,直接标记
		for(int i=0;i<n;i++) {
			if(startTime<=game[i].start) {
				ans++;
				startTime = game[i].end;
			}
		}
		
		System.out.println(ans);
	}
}

P1540 [NOIP2010 提高组] 机器翻译

假设内存中有 M 个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过 M-1,软件会将新单词存入一个未使用的内存单元;若内存中已存入 M 个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。

假设一篇英语文章的长度为 N 个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。

输入格式
共 2 行。每行中两个数之间用一个空格隔开。

第一行为两个正整数 M,N,代表内存容量和文章的长度。

第二行为 N 个非负整数,按照文章的顺序,每个数(大小不超过 1000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。

输出格式
一个整数,为软件需要查词典的次数。

输入输出样例
输入 #1复制
3 7
1 2 1 5 4 4 1
输出 #1复制
5
解题思路:先进去的先出来,赤裸裸的队列,先回去看了看自己写过的队列解题,这里列出队列的一些操作:
创建队列:

	static Queue q = (Queue) new LinkedList();

获取队列的首位置值:q.peek();
加入队尾:q.offer(e);
移除队首:q.poll();

解题思路:每次读入一个数则对这个数判断是否为true,如果真则说明直接跳过。不为真则需要先判断是否队满,队满的话就需要移除队首,同时把队首的值对应的数组值变为false,之后就是进队尾操作,同时对这个数的数组值标记为true。

package 洛谷习题;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class P1540 {
	static int m,n,ans;
	static boolean a[] = new boolean [1010];
	
	static Queue q = (Queue) new LinkedList();
	
	public static void main(String[] args) {
		Scanner in = new Scanner (System.in);
		m = in.nextInt();
		n = in.nextInt();
		
		for(int i=0;i<n;i++) {
			int j = in.nextInt();
			if(a[j]) continue;
			
			if(q.size()==m) {
				a[(int)q.peek()] = false;
				q.poll();
			}
			ans++;
			q.offer(j);
			a[j] = true;
		}
		
		System.out.println(ans);
	}
}

P1206 [USACO1.2]回文平方数 Palindromic Squares

题目描述
回文数是指从左向右念和从右向左念都一样的数。如 12321 就是一个典型的回文数。

给定一个用十进制表示的正整数 BB,输出所有 [1,300]中,它的平方用 B 进制表示时是回文数的数。

输入格式
共一行,一个单独的正整数 B。

输出格式
每行两个 B 进制的符合要求的数字,第二个数是第一个数的平方,且第二个数是回文数。

注意大于 9 的数,用字母表示。如用 A 表示 10,B 表示 11,用第 n 个大写字母表示 n+9。

输入输出样例
输入 #1复制
10
输出 #1复制
1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
264 69696
解题思路:设置一个进制转化的函数,还有一个回文数的判断函数即可

import java.util.Scanner;
public class Main {
	
	public static boolean HuiWen(StringBuffer x) {
		for(int i=0;i<x.length()/2;i++) {
			if(x.charAt(i)!=x.charAt(x.length()-i-1))
			return false;
		}
		return true;
	}
	
	public static StringBuffer Zhuan(int num,int B) {
		StringBuffer s = new StringBuffer();
		int digit;
		while(num>0) {
			digit=num%B;
			if(digit>=10) {
				s.append((char)('A'+digit-10));
			}
			else {
				s.append(digit);
			}
			num/=B;
		}
		return s.reverse();
	}
	
	public static void main(String[] args) {
		Scanner in = new Scanner (System.in);
		int n = in.nextInt();
		for(int i=1;i<300;i++) {
			StringBuffer s1 = Zhuan(i,n);
			StringBuffer s2 = Zhuan(i*i,n);
            
			if(HuiWen(s2))
				System.out.println(s1 +" "+s2);
		}
	}
}

试题 H: 走方格

问题:
在平面上有一些二维的点阵。这些点的编号就像二维数组的编号一样,从上到下依次为第 1 至第 n 行,从左到右依次为第 1 至第 m 列,每一个点可以用行号和列号来表示。现在有个人站在第 1 行第 1 列,要走到第 n 行第 m 列。只能向右或者向下走。
注意,如果行号和列数都是偶数,不能走入这一格中。问有多少种方案。

输入:
输入一行包含两个整数 n, m。

输出:
输出一个整数,表示答案。

样例输入1:
3 4

样例输出1:
2

样例输入2:
6 6

样例输出2:
0

package text1;

import java.util.Scanner;

public class dfs {
	static int n,m;
	static int ans;
	static int a[][] = new int [100][100];
	static int v[][] = new int [100][100];
	static int dx[] = {0,1};
	static int dy[] = {1,0};
	
	public static void dfs(int x,int y) {
		if(x==n&&y==m) {
			ans++;
			return;
		}
		for(int i=0;i<2;i++) {
			int tx = x+dx[i];
			int ty = y+dy[i];
			if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&v[tx][ty]==0)
			{
			if(!((tx&1)==0&&(ty&1)==0))
			{
					v[tx][ty] = 1;
					dfs(tx,ty);
					v[tx][ty] = 0;
				}
			}
		}
	}
	
	public static void main(String[] args) {
		Scanner in = new Scanner (System.in);
		n = in.nextInt();
		m = in.nextInt();
		
		if(!((n&1)==0&&(m&1)==0)) {
			dfs(1,1);
			System.out.println(ans);
		}
		else System.out.println("0");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值