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;
}

整数二分

有单调性一定可以二分,但是没有单调性也可以二分

二分模板的两种情况

  1. [l,r] 被分成 [l, mid] [mid+1, r] 的时候,即让r=mid,找左半边的时候,用mid=l+r >> 1
  2. [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;
 } 

前缀和

image-20220205091000334

差分

有 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;
}

二维差分

image-20220205232032531

image-20220205232905935

image-20220205232937923

CCF/ CSP

image-20220205232333984

每日一题

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;
    
    
}
posted @ 2022-02-05 23:31  VanHope  阅读(407)  评论(0编辑  收藏  举报