原题链接
题目描述
给你一个长度为n
( n ≥ 2 n \ge 2 n≥2)的数组arr
,你可以进行最多8
次以下的操作,让arr
中所有的元素变为0
。
- 选择一段区间 [ l , r ] [ l, r] [l,r],让区间中的元素进行异或,假设这段区间的异或和为
s
。- 将刚刚选择的区间 [ l , r ] [ l, r] [l,r]中所有的元素替换为
s
。问需要多少次操作可以让
arr
中所有的元素变为0
,并输出你每次选择的区间 [ l , r ] [l,r] [l,r],如果有多个答案,输出任意一个。思路:分类讨论+思维+位运算
n
为偶数,那么直接选择两次区间 [ 1 , n ] [1,n] [1,n]异或,最终arr
中所有的元素变为0
。n
为奇数,先选择两次区间 [ 2 , n ] [2,n] [2,n]异或,那么arr
中 [ 2 , n ] [2,n] [2,n]的元素全部变为0
,再选择两次区间 [ 1 , 2 ] [1,2] [1,2]异或,最终arr
中所有的元素变为0
。
public static void solve() throws IOException {
int n = readInt();
int[] arr = utils.nextIntArray(n);
if (n % 2 == 0) {
printWriter.println(2);
printWriter.println(1 + " " + n);
printWriter.println(1 + " " + n);
} else {
printWriter.println(4);
printWriter.println(2 + " " + n);
printWriter.println(2 + " " + n);
printWriter.println(1 + " " + 2);
printWriter.println(1 + " " + 2);
}
}
原题链接
题目描述
一个二维平面上有n
个城市,其中前k
个为主要城市。小明想要从一个城市a
到城市b
去旅游,在这期间他可以去任意的城市,如果经过的两个城市 i , j i,j i,j都是主要城市,那么期间花费为0
,如果不是,那么需要消耗 ∣ x i − x j ∣ + ∣ y i − y j ∣ |x_i - x_j| + |y_i - y_j| ∣xi−xj∣+∣yi−yj∣的花费。现在需要你求出最小花费,使得小明可以从a
到b
。思路:分类讨论+数学
- 当 k = 0 k=0 k=0或者 k = 1 k=1 k=1时,此时不需要经过其他任意城市,直接求
a
到b
的距离,因为两点之间,线段最短。- 当 k ≥ 2 k \ge 2 k≥2时,此时需要考虑是否经过主要城市,枚举离
a
最近的主要城市和离b
最近的主要城市,算出经过这两个主要城市的距离与a
直接到b
的距离取最小值即可。
public static void solve() throws IOException {
int n = readInt(), k = readInt(), s = readInt(), e = readInt();
Pair[] pairs = new Pair[n + 1];
Arrays.setAll(pairs, g -> new Pair());
for (int i = 1; i <= n; i++) {
pairs[i] = new Pair(readInt(), readInt());
}
long a = pairs[s].first, b = pairs[s].second, c = pairs[e].first, d = pairs[e].second;
long dis = getDis(a, c) + getDis(b, d);
if (k == 0 || k == 1) {
printWriter.println(dis);
} else {
long dis2 = Long.MAX_VALUE, dis3 = Long.MAX_VALUE;
int use = 0;
// 算出离a最近的城市
for (int i = 1; i <= k; i++) {
if (getDis(a, pairs[i].first) + getDis(b, pairs[i].second) < dis2) {
dis2 = getDis(a, pairs[i].first) + getDis(b, pairs[i].second);
use = i;// 避免城市重复选
}
}
// 算出离b最近的城市
for (int i = 1; i <= k; i++) {
if (i != use && getDis(c, pairs[i].first) + getDis(d, pairs[i].second) < dis3) {
dis3 = getDis(c, pairs[i].first) + getDis(d, pairs[i].second);
}
}
printWriter.println(Math.min(dis, dis2 + dis3));
}
}
// 计算两点间的距离
public static long getDis(long a, long b) {
long res = 0;
if (a >= 0 && b >= 0) {
res = Math.abs(a - b);
} else if (a <= 0 && b <= 0) {
b = Math.abs(b); a = Math.abs(a);
res = Math.abs(a - b);
} else if (a >= 0 && b <= 0) {
res = Math.abs(b) + a;
} else if (a <= 0 && b >= 0) {
res = Math.abs(a) + b;
}
return res;
}
原题链接
题目描述
有一个 n × m n × m n×m的二维矩阵M
,这个矩阵的每一行必须是一个 0 ∼ m − 1 0 \sim m-1 0∼m−1的排列,现在,我们定义这个矩阵M
第i
列的美好度 v i v_i vi表示为 m e x ( M 1 , i , M 2 , i , . . . , M n , i ) mex(M_{1,i},M_{2,i},...,M_{n,i}) mex(M1,i,M2,i,...,Mn,i),其中 m e x mex mex函数表示这一列未出现的最小的自然数。最终这个矩阵M
的美好度表示为 m e x ( v 1 , v 2 , . . . , v m ) mex(v_1,v_2,...,v_m) mex(v1,v2,...,vm)。现在,给你这个矩阵M
的行列分别为n
行和m
列,请你最大化矩阵M
的美好度并求出最终的矩阵。思路:分类讨论+思维
- 想要最大化美好度
M
,当然得尽可能地让 v 1 , v 2 , . . . , v m v_1,v_2,...,v_m v1,v2,...,vm的值可以作为一个 0 ∼ m − 1 0 \sim m-1 0∼m−1的排列,这样,矩阵M
的美好度就为 m m m,最大化M
美好度的方式就是让排列 1 ∼ m − 1 1 \sim m-1 1∼m−1不断循环移动,但最多移动 m − 1 m-1 m−1次。- 首先特判 m = 1 m=1 m=1的情况,此时矩阵的值全为
0
,那么 m e x ( M 1 , 1 , M 2 , 1 , . . . , M n , 1 ) = 1 mex(M_{1,1},M_{2,1},...,M_{n,1})=1 mex(M1,1,M2,1,...,Mn,1)=1,则 m e x ( v 1 ) = 0 mex(v_1)=0 mex(v1)=0。- 然后讨论
n
与 m − 1 m-1 m−1的关系
- n ≥ m − 1 n \ge m-1 n≥m−1,此时可以让排列移动 m − 1 m-1 m−1次,美好度最大为 m m m。
- n < m − 1 n \lt m - 1 n<m−1,此时排列无法移动 m − 1 m-1 m−1次,美好度最大为 n + 1 n+1 n+1。
public static void solve() throws IOException {
int n = readInt(), m = readInt();
int[] arr = new int[m];
for (int i = 0; i < m; i++) arr[i] = i;// 排列
int[][] map = new int[n][m];
// 特判 m = 1的情况
if (m == 1) {
printWriter.println(0);
for (int i = 0; i < n; i++) {
printWriter.println(0);
}
return;
}
int curRow = 0;
// 判断是否让排列arr移动 m - 1次
printWriter.println(n >= m - 1 ? m : n + 1);
for (int i = 1; i < m - 1 && curRow < n; i++, curRow++) {
for (int j = 0; j < m; j++) {
printWriter.print(arr[j] + " ");
}
printWriter.println();
arr = nextPermulation(arr, m);
}
for (int i = curRow; i < n; i++) {
for (int j = 0; j < m; j++) {
printWriter.print(arr[j] + " ");
}
printWriter.println();
}
}
// 构造循环移动后的新排列
public static int[] nextPermulation(int[] arr, int m) {
int t = arr[0];
for (int i = 0; i < m - 1; i++) arr[i] = arr[i + 1];
arr[m - 1] = t;
return arr;
}