acwing 基础算法课
AcWing算法基础课
模板—以题目为单位
快速排序
acwing785
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N];
int n;
void quick_sort(int q[], int l, int r) {
if(l >= r) return;
int i = l-1, j = r+1, x = q[(l+r)>>1]; // 这里x选取的时候不要使用q[l],不然容易超时
while(i < j) {
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i < j) swap(q[i], q[j]); // 如果i < j 则交换
}
quick_sort(q, l, j);
quick_sort(q, j+1, r);
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &q[i]);
quick_sort(q, 0, n-1);
for(int i = 0; i < n; i++) printf("%d ", q[i]);
return 0;
}
acwing786
快排选择第k大的数
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int q[N];
// [l, r]闭区间
int quick_select(int q[], int l, int r, int k) {
if(l >= r) return q[l];
int i = l-1, j = r+1, x = q[(l+r)>>1];
while(i < j) {
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i < j) swap(q[i], q[j]);
}
// 从l到j
int leftSize = j - l + 1;
if(k <= leftSize) quick_select(q, l, j, k);
else quick_select(q, j+1, r, k-leftSize);
}
int main()
{
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i++) scanf("%d", &q[i]);
printf("%d", quick_select(q, 0, n-1, k));
return 0;
}
归并排序
#include<iostream>
using namespace std;
const int N = 1e5+10;
int q[N], tmp[N];
int n;
void merge_sort(int q[], int l, int r){
if(l >= r) return; // 只有一个元素,不必排序,直接返回
int mid = l + r >> 1 ;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
// 合并左右两段
int i = l, j = mid+1, k = 0; // i = l, j = mid+1
while(i <= mid && j <= r) {
if(q[i] <= q[j]) tmp[k ++] = q[i ++];
else tmp[k ++] = q[j ++];
}
while(i <= mid) tmp[k ++] = q[i ++];
while(j <= r) tmp[k ++] = q[j ++];
// 复制回原数组
for(int i = 0, j = l; j <= r; i++, j++) q[j] = tmp[i];
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &q[i]);
merge_sort(q, 0, n-1);
for(int i = 0; i < n; i++) printf("%d ", q[i]);
return 0;
}
整数二分
有单调性一定可以二分,但是没有单调性也可以二分
二分模板的两种情况
- 当
[l,r]
被分成[l, mid] [mid+1, r]
的时候,即让r=mid
,找左半边的时候,用mid=l+r >> 1
- 当
[l,r]
被分成[l, mid-1] [mid, r]
的时候,即让l=mid
,找右半边的时候,用mid=l+r+1 >> 1
对于第二种情况是因为:当 l = r-1, mid = l+r>>1 还是等于l(因为cpp下取整),此时取l = mid还是l,就会导致死循环。
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
作者:yxc
链接:https://www.acwing.com/blog/content/277/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
acwing 789
#include<iostream>
using namespace std;
const int N = 100010;
int a[N];
int n, q, k;
int main()
{
scanf("%d%d", &n, &q);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
while(q--){
scanf("%d", &k);
// 查找左边界
int l = 0, r = n - 1;
while(l < r) {
int mid = l + r >> 1;
if(a[mid] >= k) r = mid;
else l = mid + 1;
}
// 如果左边界不是k,说明数组没有k,直接输出-1 -1
if(a[l] != k) cout<< "-1 -1" << endl;
else {
cout << l << " ";
// 查找右边届
int l = 0, r = n - 1;
while(l < r) {
int mid = l + r + 1>> 1;
if(a[mid] <= k) l = mid; // 因为这里是l = mid, 上面的mid 要变成 l+r+1 >> 1
else r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}
高精度加法
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector<int> add(vector<int> A, vector<int> B) {
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || i < B.size(); i++) {
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
res.push_back(t % 10);
t /= 10;
}
if(t) res.push_back(1);
return res;
}
int main()
{
string a, b;
vector<int> A, B;
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
vector<int> C = add(A, B);
for(int i = C.size()-1; i >= 0; i--) printf("%d", C[i]);
return 0;
}
高精度减法
#include<iostream>
#include<string>
#include<vector>
using namespace std;
// C = A - B
vector<int> add(vector<int> A, vector<int> B) {
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || i < B.size(); i++) {
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
res.push_back(t % 10);
t /= 10;
}
if(t) res.push_back(1);
return res;
}
// A >= B ?
// A = 123 == [3, 2, 1]
bool cmp(vector<int> A, vector<int> B)
{
if(A.size() != B.size()) return A.size() > B.size();
// A.size() == B.size()
for(int i = A.size() - 1; i >= 0; i--) {
if(A[i] != B[i]) return A[i] > B[i];
}
return true;
}
vector<int> sub(vector<int> A, vector<int> B)
{
vector<int> res;
int t = 0; // 进位
for(int i = 0; i < A.size(); i++) {
t = A[i] - t;
if(i < B.size()) t -= B[i]; // A[i] - B[i] - t;
res.push_back((t+10)%10);
if(t < 0) t = 1;
else t = 0;
}
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
int main()
{
string a, b;
vector<int> A, B;
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
// vector<int> C = add(A, B);
vector<int> C;
if(cmp(A, B)) {
C = sub(A, B);
}
else {
C = sub(B, A);
printf("-");
}
for(int i = C.size()-1; i >= 0; i--) printf("%d", C[i]);
return 0;
}
高精度乘法
#include<iostream>
#include<string>
#include<vector>
using namespace std;
// C = A - B
vector<int> add(vector<int> A, vector<int> B) {
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || i < B.size(); i++) {
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
res.push_back(t % 10);
t /= 10;
}
if(t) res.push_back(1);
return res;
}
// A >= B ?
// A = 123 == [3, 2, 1]
bool cmp(vector<int> A, vector<int> B)
{
if(A.size() != B.size()) return A.size() > B.size();
// A.size() == B.size()
for(int i = A.size() - 1; i >= 0; i--) {
if(A[i] != B[i]) return A[i] > B[i];
}
return true;
}
vector<int> sub(vector<int> A, vector<int> B)
{
vector<int> res;
int t = 0; // 进位
for(int i = 0; i < A.size(); i++) {
t = A[i] - t;
if(i < B.size()) t -= B[i]; // A[i] - B[i] - t;
res.push_back((t+10)%10);
if(t < 0) t = 1;
else t = 0;
}
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
// C = A * b;
vector<int> mul(vector<int> A, int b)
{
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || t != 0; i++) {
if(i < A.size()) t += A[i]*b;
res.push_back(t%10);
t /= 10;
}
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
int main()
{
string a;
int b;
vector<int> A;
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
// for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
// vector<int> C = add(A, B);
// vector<int> C;
// if(cmp(A, B)) {
// C = sub(A, B);
// //printf("-");
// }
// else {
// C = sub(B, A);
// printf("-");
// }
vector<int> C = mul(A, b);
for(int i = C.size()-1; i >= 0; i--) printf("%d", C[i]);
return 0;
}
高精度 / 低精度
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
// C = A - B
vector<int> add(vector<int> A, vector<int> B) {
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || i < B.size(); i++) {
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
res.push_back(t % 10);
t /= 10;
}
if(t) res.push_back(1);
return res;
}
// A >= B ?
// A = 123 == [3, 2, 1]
bool cmp(vector<int> A, vector<int> B)
{
if(A.size() != B.size()) return A.size() > B.size();
// A.size() == B.size()
for(int i = A.size() - 1; i >= 0; i--) {
if(A[i] != B[i]) return A[i] > B[i];
}
return true;
}
vector<int> sub(vector<int> A, vector<int> B)
{
vector<int> res;
int t = 0; // 进位
for(int i = 0; i < A.size(); i++) {
t = A[i] - t;
if(i < B.size()) t -= B[i]; // A[i] - B[i] - t;
res.push_back((t+10)%10);
if(t < 0) t = 1;
else t = 0;
}
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
// C = A * b;
vector<int> mul(vector<int> A, int b)
{
vector<int> res;
int t = 0;
for(int i = 0; i < A.size() || t != 0; i++) {
if(i < A.size()) t += A[i]*b;
res.push_back(t%10);
t /= 10;
}
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
// C = A / b
// 返回商, 引用r表示余数
vector<int> div(vector<int> A, int b, int& r)
{
vector<int> res;
// int t = 0;
// 从高位开始除
for(int i = A.size() - 1; i >= 0; i--) {
r = r*10 + A[i];
res.push_back(r / b);
r %= b;
}
reverse(res.begin(), res.end());
// 去掉前导0
while(res.size() > 1 && res.back() == 0) res.pop_back();
return res;
}
int main()
{
string a;
int b;
vector<int> A;
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
// for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
// vector<int> C = add(A, B);
// vector<int> C;
// if(cmp(A, B)) {
// C = sub(A, B);
// //printf("-");
// }
// else {
// C = sub(B, A);
// printf("-");
// }
// vector<int> C = mul(A, b);
int r;
vector<int> C = div(A, b, r);
for(int i = C.size()-1; i >= 0; i--) printf("%d", C[i]);
cout << endl << r;
return 0;
}
前缀和
差分
有 a[1...n]
构造一个差分数组 b[1..n] ,使得 a 是b的前缀和
#include<iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
int l, r, c;
void insert(int l, int r, int c)
{
b[l] += c;
b[r+1] -= c;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) b[i] = a[i] - a[i-1]; // 构造差分数组
while(m--) { //
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for(int i = 1; i <= n; i++) b[i] += b[i-1];
for(int i = 1; i <= n; i++) printf("%d ", b[i]);
return 0;
}
二维差分
CCF/ CSP
每日一题
2058笨拙的手指
#include<iostream>
#include<cstring>
#include<unordered_set>
using namespace std;
int get(string a, int b) // 得到b进制的十进制表示
{
int res = 0;
for(int i = 0; i < a.length(); i++) {
res = res*b + a[i] - '0';
}
return res;
}
int main()
{
string a, b;
cin >> a >> b;
unordered_set<int> S;
// 每个二进制错一位的放入set S
for(int i = 0; i < a.length(); i++) {
a[i] ^= 1;
S.insert(get(a, 2));
a[i] ^= 1;
}
// 每个三进制错误一位得到的结果看是不是在S中
for(int i = 0; i < b.length(); i++) {
for(int j = 0; j < 3; j++) {
char t = b[i];
if(j + '0' != b[i]) {
b[i] = j + '0';
int x = get(b, 3);
if(S.count(x)){
cout << x << endl;
return 0;
}
}
b[i] = t;
}
}
return 0;
}