蓝桥杯算法总结

1)归并排序:分治思想(分治法是将复杂问题分解为相同或相似的子问题,再递归地求解,利用子问题的解合并为原问题的解的方法),首先确定分界点,再分别递归排序左右,最后归并合二为一。

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
ll n;
ll a[nl];
ll q[nl];
void f(ll l,ll r){
	if(l>=r){
		return;
	}
	ll mid;
	mid=(l+r)/2;
	f(l,mid);
	f(mid+1,r);
	ll i=l,j=mid+1,k=0;
	while(i<=mid&&j<=r){
	  if(a[i]<a[j]){
	  	q[k]=a[i];
	  	k++;
	  	i++;
	  }else{
	  	q[k]=a[j];
	  	k++;
	  	j++;
	  }
	}
	while(i<=mid){
		q[k]=a[i];
		k++;
		i++;
	}
	while(j<=r){
		q[k]=a[j];
		k++;
		j++;
	}
	j=0;
	for(ll i=l;i<=r;i++){
		a[i]=q[j];
		j++;
	}
}
int main(){
	cin>>n;
	ll i,j;
	for(i=0;i<n;i++){
		cin>>a[i];
	}
    f(0,n-1);
    for(i=0;i<n;i++){
    	cout<<a[i]<<" ";
	}
}

2)日期问题:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check_valid(int year, int month, int day)
{
    if (month == 0 || month > 12) return false;
    if (day == 0) return false;
    if (month != 2)
    {
        if (day > days[month]) return false;
    }
    else
    {
        int leap = year % 100 && year % 4 == 0 || year % 400 == 0;
        if (day > 28 + leap) return false;
    }

    return true;
}

int main()
{
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);

    for (int date = 19600101; date <= 20591231; date ++ )
    {
        int year = date / 10000, month = date % 10000 / 100, day = date % 100;
        if (check_valid(year, month, day))
        {
            if (year % 100 == a && month == b && day == c ||        // 年/月/日
                month == a && day == b && year % 100 == c ||        // 月/日/年
                day == a && month == b &&year % 100 == c)           // 日/月/年
                printf("%d-%02d-%02d\n", year, month, day);
        }
    }

    return 0;
}

3)树状数组:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m;
int a[N], tr[N];
int lowbit(int x)//表明包含它的下一个位置 
{
    return x & -x;
}
void add(int x, int v)//用来初始化树状数组,并用来修改树状数组 
{
    for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;//包含x的位置都要+X 
}
int query(int x)//前缀和 
{
    int res = 0;
    for (int i = x; i>=1; i -= lowbit(i)) res += tr[i];
    return res;
}
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 ++ ) add(i, a[i]);//初始化树状数组,树状数组分很多层,越高层包含数越多 
    while (m -- )
    {
        int k, x, y;
        scanf("%d%d%d", &k, &x, &y);
        if (k == 0) printf("%d\n", query(y) - query(x - 1));
        else add(x, y);
    }
    return 0;
}

4)双指针:

//上一段时间与下一段时间有重复,区间有重复,就可以优化,可以使用双指针。 
#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
#define x first
#define y second
typedef pair<ll, ll> PII;
PII logs[nl];
ll cnt[nl];
bool st[nl];
ll n,m,k;
ll i,j;
int main(){
	cin>>n>>m>>k;
	for(ll i=0;i<n;i++){
		cin>>logs[i].x>>logs[i].y;
	}
	sort(logs,logs+n);
	for(ll i=0,j=0;i<n;i++){
		ll id=logs[i].y;
		cnt[logs[i].y]++;//区间开端需要加1
		while(logs[i].x-logs[j].x>=m){//判定是不是在区间里
			cnt[logs[j].y]--;//区间末尾需要-1
		    j++;
		}
		if(cnt[logs[i].y]>=k){
			st[id]=true;
		}
	}
	ll res=0;
	for(ll i=0;i<=100000;i++){//直接便利所有数即可,很巧妙。
		if(st[i]==true){
			cout<<i<<endl;
		}
	}

}

5)BFS:

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e3+5;
using namespace std;
typedef pair<ll,ll>PII;
ll t;
ll n,m;
#define x first
#define y second
char a[nl][nl];
ll dist[nl][nl];
ll bfs(PII start,PII end){
    queue<PII>q;
    memset(dist,-1,sizeof(dist));
    dist[start.x][start.y]=0;
    q.push(start);
    ll dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(ll i=0;i<4;i++){
            ll x=t.x+dx[i],y=t.y+dy[i];
            if(x<0||x>=n||y<0||y>=m){
                continue;
            }
            if(a[x][y]=='#'){
                continue;
            }
            if(dist[x][y]!=-1){
                continue;
            }
            dist[x][y]=dist[t.x][t.y]+1;
            q.push(make_pair(x,y));
            if(end==make_pair(x,y)){
                return dist[x][y];
            }
        }
    }
    return -1;
}
int main(){
    cin>>t;
    while(t--){
        cin>>n>>m;
        PII start,end;
        ll i,j;
        for(i=0;i<n;i++){
            for(j=0;j<m;j++) {
                cin >> a[i][j];
                if(a[i][j]=='E'){
                    start=make_pair(i,j);
                }else if(a[i][j]=='S'){
                    end=make_pair(i,j);
                }
            }
        }
        if(bfs(start,end)==-1){
            cout<<"oop!"<<endl;
        }else{
            cout<<bfs(start,end)<<endl;
        }
    }
}

7)差分:与前缀和互为补充,是前缀和逆运算,构造差分数组使得原数组为差分数组的前缀和。意义:另数组某个区间内所有数都加一个数c,只需O(1)。另差分数组的区间左端加数c,其区间右端的后一个数减去数c。

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e3+5;
using namespace std;
ll a[nl][nl];
ll b[nl][nl];
ll s[nl][nl];
void insert(ll x,ll y,ll x1,ll y1,ll z){
	b[x][y]+=z;
	b[x1+1][y]-=z;
	b[x][y1+1]-=z;
	b[x1+1][y1+1]+=z;
}
int main(){
	ll n,m,k;
	cin>>n>>m>>k;
	ll i,j;
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			cin>>a[i][j];
			insert(i,j,i,j,a[i][j]);
		}
	}
	for(i=0;i<k;i++){
		ll x,y,x1,y1,z;
		cin>>x>>y>>x1>>y1>>z;
		insert(x,y,x1,y1,z);
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+b[i][j];
		}
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			cout<<s[i][j]<<" ";
		}
		cout<<endl;
	}
}

8)前缀和:下标从一开始,方便统一计算。记录了第一个元素到第i个元素的值(一维前缀和)。降低求数组和的时间复杂度,求数组之间的和可以用前缀和数组相减的方式完成。

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e3+5;
const ll inf=1e9;
using namespace std;
ll a[nl][nl]; 
ll s[nl][nl];
int main(){
	ll n,m,k;
	cin>>n>>m>>k;
	ll i,j;
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//
		}
	}
	for(i=0;i<k;i++) {
		ll x,y,x1,y1;
		cin>>x>>y>>x1>>y1;
		cout<<s[x1][y1]-s[x-1][y1]-s[x1][y-1]+s[x-1][y-1]<<endl;
	}
}

9)二分:

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
ll a[nl];
ll n,m;
int main(){
	cin>>n>>m;
    ll i,j;
	for(i=0;i<n;i++){
		cin>>a[i];
	}	
	while(m--){
		ll k;
		cin>>k;
		ll l=0,r=n-1;
		while(l<r){
			ll mid=(r+l)/2;
			if(a[mid]>=k){
				r=mid;
			}else{
				l=mid+1;
			
		}
		if(a[r]!=k){
			cout<<"-1 -1"<<endl;
		}else{
			cout<<r<<" ";
			l=0,r=n-1;
			while(l<r){
				ll mid=(r+l+1)/2;
				if(a[mid]<=k){
					l=mid;
				}else{
					r=mid-1;
				}
			}
			cout<<r<<endl;
		} 
	}
} 

10)DFS
11)DP
12)单链表:

#include<bits/stdc++.h>
#define  ll long long
const ll nl=1e5+5;
using namespace std;
ll head,e[nl],ne[nl],idx;
void init(){
    head=-1;
    idx=0;
}
void head_cha(ll x){
    e[idx]=x;
    ne[idx]=head;
    head=idx;
    idx++;
}
void cha(ll k,ll x){
    e[idx]=x;
    ne[idx]=ne[k];
    ne[k]=idx;
    idx++;
}
void shan(ll k){
    ne[k]=ne[ne[k]];
}
int main(){
       ll n;
       cin>>n;
       init();
       while(n--){
           char s;
           cin>>s;
          // cout<<s<<endl;
           if(s=='H'){
               ll x;
               cin>>x;
               head_cha(x);
           }
           if(s=='D'){
               ll k;
               cin>>k;
               if(k==0){
                   head=ne[head];
               }else {
                   shan(k - 1);
               }
           }
           if(s=='I'){
               ll a,b;
               cin>>a>>b;
               cha(a-1,b);
           }
       }

       for(ll i=head;i!=-1;i=ne[i]){
           cout<<e[i]<<" ";
       }
}

13)并查集
14)字符串
15)高精度算法:

//高精度加法:将大数先以字符串的形式输入。借用vector数组反向存入数据。按照加法法则,累加并设置进位。
#include<bits/stdc++.h> 
using namespace std;
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);//规定前面一个数大于后面一个数 

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);//取模12取2 
        t /= 10;//加法法则,大于十进一 
    }

    if (t) C.push_back(t);
    return C;
}
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 -- ) cout << C[i]; 
    cout << endl;

    return 0;
}
//高精度减法 
#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
ll i,j;
bool cmp(vector<ll>&A,vector<ll>&B){//判断AB大小 
	if(A.size()>B.size()){
	      return true;
	}else if(A.size()<B.size()){
		return false;
	}else{
		for(i=A.size()-1;i>=0;i--){//若位数相等,则从最大位开始比较。 
			if(A[i]>B[i]){
				return true;
			}else if(A[i]<B[i]){
				return false;
			}
		}
	}
	return true;
}
vector<ll>sub(vector<ll>&A,vector<ll>&B){//做减法 
	vector<ll>c;
	ll t=0;
	for(i=0;i<A.size();i++){
		t=A[i]-t;
		if(i<B.size()){
			t-=B[i];
		}
		c.push_back((t+10)%10);//****** 
		if(t<0){//借位要减去1 
			t=1;
		}else{
		     t=0;
		}
	}
	while(c.size()>1&&c.back()==0){
		c.pop_back();
	}
	return c;
}
int main(){
	string a,b;
	vector<ll>A,B;
	cin>>a>>b;
	for(i=a.size()-1;i>=0;i--){
		A.push_back(a[i]-'0');
	}
	for(i=b.size()-1;i>=0;i--){
		B.push_back(b[i]-'0');
	}
	vector<ll>c;
	if(cmp(A,B)==true){//判断谁的值更大,本程序默认大的数减去小的数 
		c=sub(A,B);
	}else{
	    c=sub(B,A);//如果A<B,则应该返回-(B-A); 
	    cout<<'-';
	}
	for(i=c.size()-1;i>=0;i--){
		cout<<c[i];
	}
}
//高精度乘法
#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
ll i,j; 
vector<ll>mul(vector<ll>&A,int b){
	vector<ll>c;
	ll t=0;
	for(i=0;i<A.szie()||t;i++){
		if(i<A.size()){
			t+=A[i]*b;
			
		}
		c.push_back(t%10);
		t/=10;
	}
	while(c.size()>1&&c.back()==0){
		c.pop_back();
	}
	return c;
}
int main(){
	string a;
	ll b;
	cin>>a>>b;
	vector<ll>A;
	for(i=a.size()-1;i>=0;i--){
		A.push_back(a[i]-'0');
	}
	vector<ll>c=mul(A,b);
	for(i=c.size()-1;i>=0;i--){
		cout<<c[i];
	}
}

双指针算法:一种算法思想。使用这种算法思想一般先暴力枚举,观察i与j有无单调关系,再利用i与j之间规律进行优化,达到降低时间复杂度。
快速排序:利用分治思想,首先确定分界点,再调整区间,最后递归处理左右

#include <iostream>
using namespace std;

const int N = 100010;

int q[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)/2];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }

    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}

int main()
{
    int n;
    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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值