小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。
魔法机器1:如果投入x个魔法币,魔法机器会将其变为2x+1个魔法币
魔法机器2:如果投入x个魔法币,魔法机器会将其变为2x+2个魔法币
小易采购魔法神器总共需要n个魔法币,所以小易只能通过两台魔法机器产生恰好n个魔法币,小易需要你帮他设计一个投入方案使他最后恰好拥有n个魔法币。
输入描述:
输入包括一行,包括一个正整数n(1 ≤ n ≤ 10^9),表示小易需要的魔法币数量。
输出描述:
输出一个字符串,每个字符表示该次小易选取投入的魔法机器。其中只包含字符'1'和'2'。
输入例子1:
10
输出例子1:
122
思路:从后往前推
魔法王国一共有n个城市,编号为0~n-1号,n个城市之间的道路连接起来恰好构成一棵树。
小易现在在0号城市,每次行动小易会从当前所在的城市走到与其相邻的一个城市,小易最多能行动L次。
如果小易到达过某个城市就视为小易游历过这个城市了,小易现在要制定好的旅游计划使他能游历最多的城市,请你帮他计算一下他最多能游历过多少个城市(注意0号城市已经游历了,游历过的城市不重复计算)。
输入描述:
输入包括两行,第一行包括两个正整数n(2 ≤ n ≤ 50)和L(1 ≤ L ≤ 100),表示城市个数和小易能行动的次数。 第二行包括n-1个整数parent[i](0 ≤ parent[i] ≤ i), 对于每个合法的i(0 ≤ i ≤ n - 2),在(i+1)号城市和parent[i]间有一条道路连接。
输出描述:
输出一个整数,表示小易最多能游历的城市数量。
输入例子1:
5 2 0 1 2 3
输出例子1:
3
思路:先走最长的路径(树的最大深度)
* 剩下城市到达一次需要2步
* 这个思路想到了,但是没有继续深入想下去,汗、。。。猜了后直接带例子也可以确认自己的想法对不对啊。。。
但是0为什么一定是root呢?
package l4;
import java.util.Scanner;
/*
* 有3个point
* 1. 树
* 2. parent[i] ≤ i
* 3. 0一定是root,每个分支都是数组以0分界
*
* 先走最长的路径(树的最大深度)
* 剩下城市到达一次需要2步
* 这个思路想到了,但是没有继续深入想下去,汗、。。。猜了后直接带例子也可以确认自己的想法对不对啊。。。
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
int[] depth = new int[n];
int maxDepth = 0;
for(int i=1; i<n; i++) {
int t = sc.nextInt();
depth[i] = depth[t] + 1;
maxDepth = Math.max(maxDepth, depth[i]);
}
if(maxDepth >= m)
System.out.println(m+1);
else {
int leftCanGoCity = (m-maxDepth)/2;
int all = leftCanGoCity + maxDepth + 1;
System.out.println(Math.min(all, n));
}
}
}
小Q和牛博士合唱一首歌曲,这首歌曲由n个音调组成,每个音调由一个正整数表示。
对于每个音调要么由小Q演唱要么由牛博士演唱,对于一系列音调演唱的难度等于所有相邻音调变化幅度之和, 例如一个音调序列是8, 8, 13, 12, 那么它的难度等于|8 - 8| + |13 - 8| + |12 - 13| = 6(其中||表示绝对值)。
现在要对把这n个音调分配给小Q或牛博士,让他们演唱的难度之和最小,请你算算最小的难度和是多少。
如样例所示: 小Q选择演唱{5, 6}难度为1, 牛博士选择演唱{1, 2, 1}难度为2,难度之和为3,这一个是最小难度和的方案了。
输入描述:
输入包括两行,第一行一个正整数n(1 ≤ n ≤ 2000) 第二行n个整数v[i](1 ≤ v[i] ≤ 10^6), 表示每个音调。
输出描述:
输出一个整数,表示小Q和牛博士演唱最小的难度和是多少。
输入例子1:
5 1 5 6 2 1
输出例子1:
3
思路:最开始想DP,dp[i][j]表示到i位置,且i位置的音符有j来唱,但是这样递推不到前面的情况,因为需要知道某个人之前最近是唱的那个音符
写DP遇到难处,先写下递归,试想一下,要倒推到前面的情况,应该用什么来表示当前的状态?
dp[i][j]表示小Q唱到第i个音符,博士唱到第j个音符,(我们自然也知道当前唱到的是max(i,j))
public class TLE {
static int[][] memo;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for(int i=0; i<n; i++)a[i]=sc.nextInt();
memo = new int[n][n];
System.out.println(dp(a, -1, -1));
}
private static int dp(int[]a, int i, int j) {
if(i>=0 && j>=0 && memo[i][j] != 0) return memo[i][j];
int next = Math.max(i, j) + 1;
if(next == a.length) return 0;
int ret = Integer.MAX_VALUE;
ret = Math.min(ret, dp(a, next, j) + (i==-1?0:Math.abs(a[next]-a[i])));
ret = Math.min(ret, dp(a, i, next) + (j==-1?0:Math.abs(a[next]-a[j])));
if(i>=0 && j>=0) memo[i][j] = ret;
return ret;
}
}
根据递归该DP就好了
package l7;
import java.util.Scanner;
/**
* DP
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for(int i=0; i<n; i++)a[i]=sc.nextInt();
int[][] dp = new int[n+1][n+1];
for(int i=n-1; i>=0; i--) {
for(int j=n-1; j>=0; j--) {
int next = Math.max(i, j) + 1;
dp[i][j] = Integer.MAX_VALUE;
dp[i][j] = Math.min(dp[i][j], dp[next][j]+(i==0?0:Math.abs(a[next-1]-a[i-1])));
dp[i][j] = Math.min(dp[i][j], dp[i][next]+(j==0?0:Math.abs(a[next-1]-a[j-1])));
}
}
System.out.println(dp[0][0]);
}
}
这里不要根据dp[i][j]前的数据来推dp[i][j],因为到dp[i][j]的可能性很多,
要根据dp[i][j]往后推,因为就2种情况,从递归上也可以看出
n=int(input())
a=[0]+list(map(int,input().strip().split(' ')))
dp = [[0 for _ in range(n+1)] for _ in range(n+1)]
# dp[i][j] means Q to i, D to j, continue to sing, the least difficult
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
next = max(i,j)+1
dp[i][j] = min(dp[next][j]+(abs(a[i]-a[next]) if i else 0),
dp[i][next]+(abs(a[j]-a[next]) if j else 0))
print(dp[0][0])
一个合法的括号匹配序列被定义为:
1. 空串""是合法的括号序列
2. 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
3. 如果"X"是一个合法的序列,那么"(X)"也是一个合法的括号序列
4. 每个合法的括号序列都可以由上面的规则生成
例如"", "()", "()()()", "(()())", "(((()))"都是合法的。
从一个字符串S中移除零个或者多个字符得到的序列称为S的子序列。
例如"abcde"的子序列有"abe","","abcde"等。
定义LCS(S,T)为字符串S和字符串T最长公共子序列的长度,即一个最长的序列W既是S的子序列也是T的子序列的长度。
小易给出一个合法的括号匹配序列s,小易希望你能找出具有以下特征的括号序列t:
1、t跟s不同,但是长度相同
2、t也是一个合法的括号匹配序列
3、LCS(s, t)是满足上述两个条件的t中最大的
因为这样的t可能存在多个,小易需要你计算出满足条件的t有多少个。
如样例所示: s = "(())()",跟字符串s长度相同的合法括号匹配序列有:
"()(())", "((()))", "()()()", "(()())",其中LCS( "(())()", "()(())" )为4,其他三个都为5,所以输出3.
输入描述:
输入包括字符串s(4 ≤ |s| ≤ 50,|s|表示字符串长度),保证s是一个合法的括号匹配序列。
输出描述:
输出一个正整数,满足条件的t的个数。
输入
(())()
输出
3
思路:直接找出所有valid的字符串,再判断LCS
public class TLE {
static List<String> all = new ArrayList<String>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int len = s.length() / 2;
char[] cs = new char[2*len];
dfs(len, 0, 0, cs, 0);
int max = 0, cnt = 0;
for(String t : all) {
if(s.equals(t)) continue;
int tmp = getLCS(s, t);
if(tmp > max) {
max = tmp;
cnt = 1;
} else if(tmp == max) {
cnt ++;
}
}
System.out.println(cnt);
}
private static int getLCS(String s, String t) {
char[] cs1 = s.toCharArray(), cs2 = t.toCharArray();
int[][] dp = new int[1+cs1.length][1+cs2.length];
for(int i=1; i<=cs1.length; i++){
for(int j=1; j<=cs2.length; j++) {
if(cs1[i-1] == cs2[j-1])
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
return dp[cs1.length][cs2.length];
}
private static void dfs(int len, int i, int j, char[] cs, int k) {
if(k == cs.length) {
all.add(new String(cs));
return;
}
if(i<len) {
cs[k] = '(';
dfs(len, i+1, j, cs, k+1);
}
if(i>j) {
cs[k] = ')';
dfs(len, i, j+1, cs, k+1);
}
}
}
换一个角度,先把最大LCS的条件先用掉
* 当且仅当修改距离为 1 时 LCS 最大
package l6;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
/*
* 换一个角度,先把最大LCS的条件先用掉
* 当且仅当修改距离为 1 时 LCS 最大
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
// get all possible max-LCS String using stringbuilder
Set<String> set = new HashSet<String>();
for(int i=0; i<s.length(); i++) {
StringBuilder sb = new StringBuilder(s);
char c = sb.charAt(i);
sb.deleteCharAt(i);
for(int j=0; j<s.length(); j++) {
sb.insert(j, c);
if(valid(sb.toString()))
set.add(sb.toString());
sb.deleteCharAt(j);
}
}
System.out.println(set.size()-1);
}
private static boolean valid(String s) {
char[] cs = s.toCharArray();
int left = 0;
for(char c : cs) {
if(c == '(') left++;
else left--;
if(left < 0) return false;
}
return left == 0;
}
}
s=input()
ss=set()
def ok(t):
cnt=i=0
while i<len(t):
cnt+= (1 if t[i]=='(' else -1)
if cnt<0: return False
i += 1
return cnt==0
# pop right
for i in range(len(s)):
for j in range(i+1,len(s)):
t=s[:i]+s[i+1:j]+s[i]+s[j:]
if ok(t): ss.add(t)
# pop left
for i in range(len(s)):
for j in range(i):
t=s[:j]+s[i]+s[j:i]+s[i+1:]
if ok(t): ss.add(t)
print(len(ss) if s not in ss else len(ss)-1)
把前面有个字符放到后面,或者把后面有个字符放到前面
链接:https://www.nowcoder.com/questionTerminal/d3f26db0325444078717cc802e0056d8
来源:牛客网
小易正在玩一款新出的射击游戏,这个射击游戏在一个二维平面进行,小易在坐标原点(0,0),平面上有n只怪物,每个怪物有所在的坐标(x[i], y[i])。小易进行一次射击会把x轴和y轴上(包含坐标原点)的怪物一次性消灭。
小易是这个游戏的VIP玩家,他拥有两项特权操作:
1、让平面内的所有怪物同时向任意同一方向移动任意同一距离
2、让平面内的所有怪物同时对于小易(0,0)旋转任意同一角度
小易要进行一次射击。小易在进行射击前,可以使用这两项特权操作任意次。
输入描述:
输入包括三行。 第一行中有一个正整数n(1 ≤ n ≤ 50),表示平面内的怪物数量。 第二行包括n个整数x[i](-1,000,000 ≤ x[i] ≤ 1,000,000),表示每只怪物所在坐标的横坐标,以空格分割。 第二行包括n个整数y[i](-1,000,000 ≤ y[i] ≤ 1,000,000),表示每只怪物所在坐标的纵坐标,以空格分割。
输出描述:
输出一个整数表示小易最多能消灭多少只怪物。
输入
5 0 -1 1 1 -1 0 -1 -1 1 1
输出
5
最开始还想先求出所有的斜率放到Map里面,然后后面再遍历Map,但是存在2条直线相交的点在原来的点之中,
其实这样麻烦的话就直接循环遍历了,反正复杂度都差不多
注意:不要用除法求斜率,会出现inf的情况,转化为乘法来判断就好了
package l8;
import java.util.Scanner;
/**
* 可以把class A中的List改为截距或者一个点的集合
* 然后每次都要判断,垂直的2条直线相交的点是不是在原来那些点中出现过
*
* 这种近乎暴力的方法绕那么多
* 还不如直接循环
* 前2层循环定出一条直线,第3层循环+斜率定出来一条直线
* 第4层循环判断是否落在这2条直线上
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n], b = new int[n];
for(int i=0; i<n; i++)a[i]=sc.nextInt();
for(int i=0; i<n; i++)b[i]=sc.nextInt();
if(n < 3) {
System.out.println(n);
return;
}
int max = 0;
for(int i=0; i<n; i++) {
for(int j=i+1; j<n; j++) {
double k1 = (b[i]-b[j]) / (a[i]-a[j]+0.0);
double b1 = b[i] - k1 * a[i];
for(int k=j+1; k<n; k++) {
int cnt = 0;
for(int l=k+1; l<n; l++) {
if(k1*a[l]+b1 == b[l]) {
cnt ++;
continue;
}
double k2 = (b[l]-b[k]) / (a[l]-a[k]+0.0);
if(k2 * k1 == -1) cnt ++;
}
max = Math.max(max, cnt);
}
}
}
System.out.println(max+3);
}
}