存在n+1个房间,每个房间依次为房间1 2 3…i,每个房间都存在一个传送门,i房间的传送门可以把人传送到房间pi(1<=pi<=i),现在路人甲从房间1开始出发(当前房间1即第一次访问),每次移动他有两种移动策略:
A. 如果访问过当前房间 i 偶数次,那么下一次移动到房间i+1;
B. 如果访问过当前房间 i 奇数次,那么移动到房间pi;
现在路人甲想知道移动到房间n+1一共需要多少次移动;
思路:
参考 https://blog.csdn.net/flushhip/article/details/79458502
dp[i] = dp[i-1]+1 // 第一次从i-1移动到i
+1 // 从i传送到p[i]位置
+dp[i-1] - dp[ p[i]-1 ] - 1 //从p[i]位置移动到i-1
+ 1 //第二次从i-1移动到i
第三步中:dp[ p[i]-1 ]+1可以理解为,从1到p[i]位置需要移动的步数
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] p = new int[n+1];
for(int i=1;i<=n;i++){
p[i] = scanner.nextInt();
}
scanner.close();
long dp[] = new long[n+1];
for(int i=1;i<=n;i++){
dp[i] = (dp[i-1]*2%1000000007-dp[p[i]-1]+2)%1000000007;
}
System.out.println(dp[n]%1000000007);
}
}
题目描述:
有三只球队,每只球队编号分别为球队1,球队2,球队3,这三只球队一共需要进行 n 场比赛。现在已经踢完了k场比赛,每场比赛不能打平,踢赢一场比赛得一分,输了不得分不减分。已知球队1和球队2的比分相差d1分,球队2和球队3的比分相差d2分,每场比赛可以任意选择两只队伍进行。求如果打完最后的 (n-k) 场比赛,有没有可能三只球队的分数打平。
思路:
分类讨论。
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
for(int i=0;i<t;i++){
boolean isSame =
possibleSame(scanner.nextLong(),scanner.nextLong()
,scanner.nextLong(),scanner.nextLong());
if(isSame){
System.out.println("yes");
}else{
System.out.println("no");
}
}
scanner.close();
}
public static boolean possibleSame(long n,long k,long d1,long d2){
// 1 < 2 < 3
long temp = k-d1-(d1+d2);
if(temp>=0&&temp%3==0){
long left = n-k-(d1+d2+d2);
if(left>=0&&left%3==0){
return true;
}
}
// 1 < 2 > 3
if(d1+d1-d2<0){
temp = k-(d2+d2-d1);
}else if(d2+d2-d1<0){
temp = k-(d1+d1-d2);
}else{
temp = k-Math.min(d1+d1-d2,d2+d2-d1);
}
if(temp>=0&&temp%3==0){
long left = n-k-(d1+d2);
if(left>=0&&left%3==0){
return true;
}
}
// 1 > 2 > 3
temp = k-d2-(d1+d2);
if(temp>=0&&temp%3==0){
long left = n-k-(d1+d1+d2);
if(left>=0&&left%3==0){
return true;
}
}
// 1 > 2 < 3
temp = k-d1-d2;
if(temp>=0&&temp%3==0){
long left = n-k-Math.max(d1+d1-d2,d2+d2-d1);
if(left>=0&&left%3==0){
return true;
}
}
return false;
}
}
题目描述:
有一个仅包含’a’和’b’两种字符的字符串s,长度为n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。
思路:
以替换a为例,那么我们需要找到所有a的位置pos[n],连续的最长的b就是a[i+m+1]-a[i]-1中最长的那一个子序列。
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
scanner.nextLine();
char[] str = scanner.nextLine().toCharArray();
System.out.println(Math.max(getLength(n,m,str,'a'),getLength(n,m,str,'b')));
}
public static int getLength(int n,int m,char[] str,char c){
ArrayList<Integer> pos = new ArrayList<>();
for(int i=0;i<n;i++){
if(str[i]==c){
pos.add(i);
}
}
if(pos.size()<=m){
return n;
}
pos.add(str.length);
int result = pos.get(m);
for(int i=m+1;i<pos.size();i++){
result = Math.max(result,pos.get(i)-pos.get(i-m-1)-1);
}
return result;
}
}
题目描述:
二阶魔方又叫小魔方,是222的立方形结构。每一面都有4个块,共有24个块。每次操作可以将任意一面逆时针或者顺时针旋转90°,如将上面逆时针旋转90°操作如下。
Nero在小魔方上做了一些改动,用数字替换每个块上面的颜色,称之为数字魔方。魔方上每一面的优美度就是这个面上4个数字的乘积,而魔方的总优美度就是6个面优美度总和。
现在Nero有一个数字魔方,他想知道这个魔方在操作不超过5次的前提下能达到的最大优美度是多少。
魔方展开后每一块的序号如下图:
思路:
参考 https://blog.csdn.net/cswhit/article/details/87110959
写出六个面转动的交换,利用递归求最大值
代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextInt()){
int[] num = new int[24];
for(int i=0;i<24;i++){
num[i] = scanner.nextInt();
}
System.out.println(maxGrace(num,5));
}
}
public static int maxGrace(int[] num,int times){
int grace = calculateGrace(num);
if(times==0){
return grace;
}
int[] numcp = new int[24];
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnLeft(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnRight(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnTop(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnBottom(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnFront(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
for(int i=0;i<24;i++){
numcp[i] = num[i];
}
turnBack(numcp);
grace = Math.max(maxGrace(numcp,times-1),grace);
return grace;
}
public static void turnLeft(int[] num){
change(num,0,6,16,20);
change(num,2,12,18,22);
change(num,4,5,11,10);
}
public static void turnRight(int[] num){
change(num,1,7,17,21);
change(num,3,13,19,23);
change(num,9,8,14,15);
}
public static void turnTop(int[] num){
change(num,4,6,8,23);
change(num,5,7,9,22);
change(num,2,3,1,0);
}
public static void turnBottom(int[] num){
change(num,10,12,14,21);
change(num,11,13,15,20);
change(num,16,17,19,18);
}
public static void turnFront(int[] num){
change(num,11,2,8,17);
change(num,5,3,14,16);
change(num,6,7,13,12);
}
public static void turnBack(int[] num){
change(num,10,0,9,19);
change(num,4,1,15,18);
change(num,22,23,21,20);
}
public static void change(int[] num,int i,int j,int k,int m){
int temp = num[i];
num[i] = num[j];
num[j] = num[k];
num[k] = num[m];
num[m] = temp;
}
public static int calculateGrace(int[] n){
return n[0]*n[1]*n[2]*n[3]
+n[4]*n[5]*n[10]*n[11]
+n[8]*n[9]*n[14]*n[15]
+n[6]*n[7]*n[12]*n[13]
+n[16]*n[17]*n[18]*n[19]
+n[20]*n[21]*n[22]*n[23];
}
}
题目描述:
有一个推箱子的游戏, 一开始的情况如下图:
上图中, ‘.’ 表示可到达的位置, ‘#’ 表示不可到达的位置,其中 S 表示你起始的位置, 0表示初始箱子的位置, E表示预期箱子的位置,你可以走到箱子的上下左右任意一侧, 将箱子向另一侧推动。如下图将箱子向右推动一格;
…S0… -> …S0.
注意不能将箱子推动到’#'上, 也不能将箱子推出边界;
现在, 给你游戏的初始样子, 你需要输出最少几步能够完成游戏, 如果不能完成, 则输出-1。
思路:
参考 https://blog.csdn.net/yuanxu716/article/details/78286266
(还没有完全理解,待以后补充)
代码:
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()){
String[] token = scanner.nextLine().split(" ");
int n = Integer.parseInt(token[0]);
int m = Integer.parseInt(token[1]);
char[][] matrix = new char[n][m];
int x = -1,y = -1,bx = -1,by = -1;
for(int i=0;i<n;i++){
String input = scanner.nextLine();
for(int j=0;j<m;j++){
matrix[i][j] = input.charAt(j);
if(matrix[i][j]=='S'){
x=i;
y=j;
}
if(matrix[i][j]=='0'){
bx=i;
by=j;
}
}
}
ArrayList<ArrayList<Integer>> next = new ArrayList<>();
//{-1,0},{1,0},{0,-1},{0,1}
ArrayList<Integer> a1 = new ArrayList<>();
a1.add(-1);a1.add(0);
ArrayList<Integer> a2 = new ArrayList<>();
a2.add(1);a2.add(0);
ArrayList<Integer> a3 = new ArrayList<>();
a3.add(0);a3.add(-1);
ArrayList<Integer> a4 = new ArrayList<>();
a4.add(0);a4.add(1);
next.add(a1);
next.add(a2);
next.add(a3);
next.add(a4);
//System.out.println(next);
ConcurrentLinkedQueue<ArrayList<Integer>> queue = new ConcurrentLinkedQueue<>();
ArrayList<Integer> a = new ArrayList<>();
a.add(x);a.add(y);a.add(bx);a.add(by);
queue.offer(a);
//System.out.println(queue);
int st[][][][] = new int[50][50][50][50];
st[x][y][bx][by] = 1;
while(!queue.isEmpty()){
ArrayList<Integer> pb = queue.poll();
x = pb.get(0);
y = pb.get(1);
bx = pb.get(2);
by = pb.get(3);
for(int i=0;i<next.size();i++){
int nx = x+next.get(i).get(0),
ny = y+next.get(i).get(1);
int nnx = nx+next.get(i).get(0),
nny = ny+next.get(i).get(1);
// 玩家从开始位置走到箱子的位置
if(valid(matrix,nx,ny)&&(nx!=bx||ny!=by)&&st[nx][ny][bx][by]==0){
st[nx][ny][bx][by] = st[x][y][bx][by]+1;
ArrayList<Integer> list = new ArrayList<>();
list.add(nx);list.add(ny);list.add(bx);list.add(by);
queue.offer(list);
continue;
}
// 玩家把箱子推到指定位置
else if(valid(matrix,nnx,nny)&&(nx==bx&&ny==by)&&st[nx][ny][nnx][nny]==0){
st[nx][ny][nnx][nny] = st[x][y][bx][by]+1;
if(matrix[nnx][nny]=='E'){
System.out.println(st[nx][ny][nnx][nny]-1);
return;
}
ArrayList<Integer> list = new ArrayList<>();
list.add(nx);list.add(ny);list.add(nnx);list.add(nny);
queue.offer(list);
}
}
}
System.out.println(-1);
return;
}
}
public static boolean valid(char[][] matrix,int x,int y){
if (x >= 0 && x < matrix.length && y >= 0 && y < matrix[0].length && matrix[x][y] != '#')
return true;
return false;
}
}