A-Guess The Number
知识点
m=(l+r)/2
可能会发生溢出。因此采用m=l+(r-l)/2
或m=l+((r-l)>>1)
- 输出结束后刷新缓冲区
代码实现
C++
#include <iostream>
#define ull unsigned long long
using namespace std;
int main() {
ull l = 0, r = 0xffffffffffffffff;
while (l <= r) {
ull m = l + (r - l) / 2;
cout << m << endl;
string res;
cin >> res;
if (res == "TooBig") {
r = m - 1;
} else if (res == "TooSmall") {
l = m + 1;
} else {
return 0;
}
}
return 0;
}
B-Inversion
知识点
- 逆序对个数。基本思路是二重循环,时间复杂度 O ( n 2 ) O(n^2) O(n2)会超时。因此选择采用归并排序的形式来分治优化,达到 O ( n log n ) O(n\log n) O(nlogn)的时间复杂度
拓展知识
这一题其实可以采用线段树或者离散化树状数组等高级算法知识,但是时间可能并不优于分治策略
相关链接
https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solutions/216984/shu-zu-zhong-de-ni-xu-dui-by-leetcode-solution/
https://oi-wiki.org/ds/seg/#%E7%BA%BF%E6%AE%B5%E6%A0%91
相关链接
力扣原题:https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/description/
代码实现
C++分治策略
#include <iostream>
#include <vector>
using namespace std;
void mergeSort(vector<int> &nums, int l, int r, unsigned long long &ans);
void merge(vector<int> &nums, int l, int m, int r, unsigned long long &ans);
int main() {
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; i++) {
int tmp;
cin >> tmp;
nums[i] = tmp;
}
unsigned long long ans = 0;
mergeSort(nums, 0, n - 1, ans);
cout << ans << endl;
}
void merge(vector<int> &nums, int l, int m, int r, unsigned long long &ans) {
vector<int> tmp1(m - l + 1), tmp2(r - m);
for (int i = l; i <= m; i++) {
tmp1[i - l] = nums[i];
}
for (int i = m + 1; i <= r; i++) {
tmp2[i - m - 1] = nums[i];
}
int i = 0, j = 0;
while (i < m - l + 1 && j < r - m) {
if (tmp1[i] <= tmp2[j]) {
nums[l + i + j] = tmp1[i];
i++;
} else {
nums[l + i + j] = tmp2[j];
j++;
ans += m - l + 1 - i;
}
}
while (i < m - l + 1) {
nums[l + i + j] = tmp1[i];
i++;
}
while (j < r - m) {
nums[l + i + j] = tmp2[j];
j++;
}
}
void mergeSort(vector<int> &nums, int l, int r, unsigned long long &ans) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(nums, l, m, ans);
mergeSort(nums, m + 1, r, ans);
merge(nums, l, m, r, ans);
}
}
Java线段树
import java.util.*;
public class Main {
static long[] d;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = 0;
n = in.nextInt();
long ret = 0;
d = new long[n * 4];
for (int i = 0; i < n; i++) {
int x = in.nextInt();
add(1, 1, n + 1, x);
ret += query(1, 1, n + 1, x + 1, n);
}
System.out.println(ret);
}
static void add(int p, int l, int r, int num) {
if (l == r) {
d[p]++;
return;
}
int mid = l + ((r - l) >> 1);
if (num <= mid) {
add(p * 2, l, mid, num);
} else {
add(p * 2 + 1, mid + 1, r, num);
}
d[p] = d[p * 2] + d[p * 2 + 1];
}
static long query(int p, int l, int r, int L, int R) {
if (L <= l && R >= r) {
return d[p];
}
long sum = 0;
int mid = l + ((r - l) >> 1);
if (L <= mid) {
sum += query(p * 2, l, mid, L, R);
}
if (R > mid) {
sum += query(p * 2 + 1, mid + 1, r, L, R);
}
return sum;
}
}
C-Points
知识点
- 不太好想的分治策略。对点按x坐标排序,然后分成左右两份分治,得到左边的最小距离和右边的最小距离,由此得到两边的最小距离,归并过程中,我们只要考虑跨越中间点的最小距离即可,从中间开始向两端遍历将点压入栈中,发现距离大于之前记录的最小距离就可停止遍历,然后将栈中的点按y排序并计算距离
- 优化技巧:我们能不能先不开方,最后再开方(开方的性能损耗非常大)?可惜我试了很久没成功。
相关链接
洛谷原题:https://www.luogu.com.cn/problem/P1429
代码实现
c++
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>
#define int long long
using namespace std;
inline double length(vector<int> p1, vector<int> p2);
double divide_conquer(vector<vector<int>> &points, int l, int r);
signed main() {
int n;
cin >> n;
vector<vector<int>> points(n, vector<int>(2));
for (int i = 0; i < n; i++) {
cin >> points[i][0] >> points[i][1];
}
sort(points.begin(), points.end());
printf("%.4f", divide_conquer(points, 0, n - 1));
}
inline double length(vector<int> p1, vector<int> p2) {
return sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));
}
double divide_conquer(vector<vector<int>> &points, int l, int r) {
if (l == r - 1) {
return length(points[l], points[r]);
}
if (l < r) {
int m = l + (r - l) / 2;
double l1 = divide_conquer(points, l, m);
double l2 = divide_conquer(points, m + 1, r);
double ans = min(l1, l2);
vector<vector<int>> tmp{points[m]};
int midX = points[m][0];
for (int i = m - 1;
i >= l && midX - points[i][0] < ans;
tmp.push_back(points[i]), i--)
;
for (int i = m + 1;
i <= r && points[i][0] - midX < ans;
tmp.push_back(points[i]), i++)
;
sort(tmp.begin(), tmp.end(),
[](vector<int> &p1, vector<int> &p2) { return p1[1] < p2[1]; });
int tmpN = tmp.size();
for (int i = 0; i < tmpN; i++) {
for (int j = i + 1;
j < tmpN && tmp[j][1] - tmp[i][1] < ans;
ans = min(ans, length(tmp[i], tmp[j])), j++)
;
}
return ans;
}
return 0x7fffffff;
}
D-Strassen
知识点
- Strassen公式
- 优化技巧:在矩阵计算的基本方法中,我们一般会按i-j-k的方式去遍历, O ( n 3 ) O(n^3) O(n3)显然会超时,但如果我们采用i-k-j的方式去遍历呢?提示:可以减少向内存中读取数据的次数,极大优化时间,与Strassen算法不相上下
代码实现
c++ Strassen算法
#include <iostream>
#include <vector>
#define int long long
using namespace std;
inline vector<vector<int> > sub_matrix(const vector<vector<int> > &m1, int x1, int y1,
const vector<vector<int> > &m2, int x2, int y2, int nn);
vector<vector<int> > mul_matrix(const vector<vector<int> > &m1, int x1, int y1,
const vector<vector<int> > &m2, int x2, int y2, int nn);
inline vector<vector<int> > add_matrix(const vector<vector<int> > &m1, int x1, int y1,
const vector<vector<int> > &m2, int x2, int y2, int nn);
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
cin >> n;
vector a(n, vector<int>(n));
vector b(n, vector<int>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> b[i][j];
}
}
for (auto res = mul_matrix(a, 0, 0, b, 0, 0, n); const auto &row: res) {
for (const auto v: row) {
cout << v << " ";
}
cout << endl;
}
}
inline vector<vector<int> > sub_matrix(const vector<vector<int> > &m1, const int x1, const int y1,
const vector<vector<int> > &m2, const int x2, const int y2,
const int nn) {
vector<vector<int> > ret(nn, vector<int>(nn));
for (int i = 0; i < nn; i++) {
for (int j = 0; j < nn; j++) {
ret[i][j] = m1[x1 + i][y1 + j] - m2[x2 + i][y2 + j];
}
}
return ret;
}
inline vector<vector<int> > add_matrix(const vector<vector<int> > &m1, const int x1, const int y1,
const vector<vector<int> > &m2, const int x2, const int y2,
const int nn) {
vector<vector<int> > ret(nn, vector<int>(nn));
for (int i = 0; i < nn; i++) {
for (int j = 0; j < nn; j++) {
ret[i][j] = m1[x1 + i][y1 + j] + m2[x2 + i][y2 + j];
}
}
return ret;
}
vector<vector<int> > mul_matrix(const vector<vector<int> > &m1, const int x1, const int y1,
const vector<vector<int> > &m2, const int x2, const int y2,
const int nn) {
if (nn <= 128) {
vector ret(nn, vector<int>(nn));
for (int i = 0; i < nn; ++i) {
for (int j = 0; j < nn; ++j) {
int tmp = 0;
for (int k = 0; k < nn; ++k) {
tmp += m1[x1 + i][y1 + k] * m2[x2 + k][y2 + j];
}
ret[i][j] = tmp;
}
}
return ret;
}
// divide
const int tn = nn / 2;
auto tmp = sub_matrix(m2, x2, y2 + tn, m2, x2 + tn, y2 + tn, tn);
const auto p1 = mul_matrix(m1, x1, y1, tmp, 0, 0, tn);
tmp = add_matrix(m1, x1, y1, m1, x1, y1 + tn, tn);
const auto p2 = mul_matrix(tmp, 0, 0, m2, x2 + tn, y2 + tn, tn);
tmp = add_matrix(m1, x1 + tn, y1, m1, x1 + tn, y1 + tn, tn);
const auto p3 = mul_matrix(tmp, 0, 0, m2, x2, y2, tn);
tmp = sub_matrix(m2, x2 + tn, y2, m2, x2, y2, tn);
const auto p4 = mul_matrix(m1, x1 + tn, y1 + tn, tmp, 0, 0, tn);
tmp = add_matrix(m1, x1, y1, m1, x1 + tn, y1 + tn, tn);
auto tmp2 = add_matrix(m2, x2, y2, m2, x2 + tn, y2 + tn, tn);
const auto p5 = mul_matrix(tmp, 0, 0, tmp2, 0, 0, tn);
tmp = sub_matrix(m1, x1, y1 + tn, m1, x1 + tn, y1 + tn, tn);
tmp2 = add_matrix(m2, x2 + tn, y2, m2, x2 + tn, y2 + tn, tn);
const auto p6 = mul_matrix(tmp, 0, 0, tmp2, 0, 0, tn);
tmp = sub_matrix(m1, x1, y1, m1, x1 + tn, y1, tn);
tmp2 = add_matrix(m2, x2, y2, m2, x2, y2 + tn, tn);
const auto p7 = mul_matrix(tmp, 0, 0, tmp2, 0, 0, tn);
// merge
vector ret(nn, vector<int>(nn));
for (int i = 0; i < tn; ++i) {
for (int j = 0; j < tn; ++j) {
ret[i][j] = p5[i][j] + p4[i][j] - p2[i][j] + p6[i][j];
}
}
for (int i = 0; i < tn; ++i) {
for (int j = tn; j < nn; ++j) {
ret[i][j] = p1[i][j - tn] + p2[i][j - tn];
}
}
for (int i = tn; i < nn; ++i) {
for (int j = 0; j < tn; ++j) {
ret[i][j] = p3[i - tn][j] + p4[i - tn][j];
}
}
for (int i = tn; i < nn; ++i) {
for (int j = tn; j < nn; ++j) {
ret[i][j] = p1[i - tn][j - tn] + p5[i - tn][j - tn] - p3[i - tn][j - tn] -
p7[i - tn][j - tn];
}
}
return ret;
}
Java 暴力
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = 0;
n = in.nextInt();
int[][] a = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = in.nextInt();
}
}
int[][] b = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
b[i][j] = in.nextInt();
}
}
int[][] c = new int[n][n];
for (int i = 0; i < n; i++) {
for (int k = 0; k < n; k++) {
int tmp = a[i][k];
for (int j = 0; j < n; j++) {
c[i][j] += tmp * b[k][j];
}
}
}
PrintWriter out = new PrintWriter(System.out);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
out.print(c[i][j]);
out.print(" ");
}
out.println();
}
out.flush();
in.close();
}
}