算法重新刷题

基础算法

前缀和

一维前缀和

[USACO16JAN] Subsequences Summing to Sevens S - 洛谷

这一题主要是需要结合数学知识来求解,

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

using namespace std;

const int N = 50010;

int n;
int s[N], l[7], r[7];

int main() {
    scanf("%d", &n);

    for (int i = 1; i <= n; i ++) {
        int cur;
        scanf("%d", &cur);
        // 初始化前缀和矩阵
        s[i] = (s[i - 1] + cur) % 7;
    }
    // 从右往左,记录7的每个余数的最左边的坐标值
    for (int i = n; i ; i --) l[s[i]] = i;
    // 从左往右,记录7的每个余数的最右边的坐标值
    for (int i = 1; i <= n; i ++) r[s[i]] = i;
    l[0] = 0;

    int res = 0;
    for (int i = 0; i <= 6; i ++) {
        if (r[i]) res = max(res, r[i] - l[i]);
    }

    printf("%d\n", res);

    return 0;
}

二维前缀和

核心的原理

模板题
活动 - AcWing

例题

最大正方形 - 洛谷

这个题的N是100,比较小,可以用三重循环通过;故枚举正方形的边长,记作len
这个题的(x1,y1)等于(i,j) 这个题的(x2,y2)相当于(i+len,j+len)

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

using namespace std;

const int N = 510;
int  a[N][N],s[N][N];
int n,m;

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}
	}
	
	//判断正方形 这个正方形里面的和是变长的平方
	// 枚举最大长度
    int res = 0;
    for (int i = 1; i <= n; i ++){
        for (int j = 1; j <= m; j ++) {
            for (int len = 0; i + len <= n && j + len <= m; len ++) {
                if (s[i + len][j + len] - s[i - 1][j + len] - s[i + len][j - 1] + s[i - 1][j - 1] == (len + 1) * (len + 1)){
                    res = max(len + 1, res);
                }
            }
        }
    }           
	cout<<res<<endl;
	
	
	return 0;
}

二维前缀和之固定边长的正方形
[HNOI2003] 激光炸弹 - 洛谷

#include<iostream>
#include<algorithm>
using namespace std;
int n, m;
int s[5050][5050];
int res = 0;



int main()
{
	cin >> n >> m;
	while (n--)
	{
		int x, y, v;
		cin >> x >> y >> v;
		s[x + 1][y + 1] += v;
	}

	for (int i = 1; i <= 5001; i++)
	{
		for (int j = 1; j <= 5001; j++)
		{
			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
		}
	}

	for (int i = m; i <= 5001; i++)
		for (int j = m; j <= 5001; j++)
		{
			//标准
			int value = s[i][j] - s[i - m][j] - s[i][j - m] + s[i - m][j - m];
			res = max(res, value);
		}
	printf("%d", res);

	return 0;
}

差分

一维差分

[Poetize6] IncDec Sequence - 洛谷

这个题里面的数学推理我现在都还没看明白

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
ll a[N];
ll b[N];
ll n;
int main()
{
	cin>>n;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	ll x,y;
	x=y=0;
	for(ll i=1;i<n;i++)
	{
		b[i]=a[i+1]-a[i];
		if(b[i]<0)x-=b[i];
		else y+=b[i];
	}
	cout<<max(x,y)<<endl;
	cout<<abs(x-y)+1<<endl;
	return 0;
}

二维差分

模板题

活动 - AcWing

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
//差分矩阵为什么是这个
void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}
// void insert(int x1, int y1, int x2, int y2, int c)
// {
//     b[x1][y1] += c;
//     b[x2 + 1][y1] -= c;
//     b[x1][y2 + 1] -= c;
//     b[x2 + 1][y2 + 1] += c;
// }
int main()
{
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
            
    //初始化差分数组
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            insert(i, j, i, j, a[i][j]);      //构建差分数组
        }
    }
    while (q--)
    {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];  //二维前缀和
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

 洛谷地毯 - 洛谷

在模版的基础上稍微变一下形即可
 

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
//差分矩阵为什么是这个
void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}
// void insert(int x1, int y1, int x2, int y2, int c)
// {
//     b[x1][y1] += c;
//     b[x2 + 1][y1] -= c;
//     b[x1][y2 + 1] -= c;
//     b[x2 + 1][y2 + 1] += c;
// }
int main()
{
    int n, m, q;
    cin >> n >> m;
            
    //初始化差分数组
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            insert(i, j, i, j, 0);      //构建差分数组
        }
    }
    while (m--)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        insert(x1, y1, x2, y2, 1);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];  //二维前缀和
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

贪心 

与排序有关的贪心(注意排序的写法)

结构体排序(记忆一下)

[USACO1.3] 混合牛奶 Mixing Milk - 洛谷

bool cmp(cow farmer1,cow farmer2)
{
	return farmer1.p<farmer2.p;
}
也就是bool cmp(结构体名称 实例1,结构体名称 实例2)
{
    return 实例1的某个成员<实例2的某个成员;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
struct cow {
	int p;
	int maxnum;
}farmer[N];
bool cmp(cow farmer1,cow farmer2)
{
	return farmer1.p<farmer2.p;
}

int main()
{
	int m,n;
	int sum = 0;
	cin >> m>> n;
	for (int i = 0; i < n; i++)
	{
		cin >> farmer[i].p>>farmer[i].maxnum;
	}
	sort(farmer,farmer+n,cmp);
	
	//需要m牛奶
	int mark=0;
	while(farmer[mark].maxnum<m)
	{
		m-=farmer[mark].maxnum;
		sum+=farmer[mark].p*farmer[mark].maxnum;
		mark++;
	 } 
	 sum+=farmer[mark].p*m;
	 cout<<sum<<endl;
	
	return 0;
}

 双指针算法

活动 - AcWing

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int a[N],cnt[N];
int n;

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    
    int res=0;
    for(int i=0,j=0;i<n;i++)
    {
        cnt[a[i]]++;
        while(cnt[a[i]]>1)
        {
            cnt[a[j]]--;//左边
            j++;
        }
        res=max(res,i-j+1);
    }
    cout<<res<<endl;

    
    return 0;
}

两个指针都要有更新的操作!

数据结构

链表

算法题中一般使用数组来模拟链表(链式前向星),带头结点

单链表

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 1e6 + 10;

int head;
int e[N], ne[N], idx;

void init() {
    head = -1;
    idx = 0;
}

void add_to_head(int x) { // 在头部加一个结点
    e[idx] = x;
    ne[idx] = head;
    head = idx++;
}

void add(int k, int x) {
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx++;
}

void remove(int k) {
    ne[k] = ne[ne[k]];
}

int main() {
    int m;
    scanf("%d", &m); // 使用scanf加快输入
    init(); // 初始化链表
    while (m--) {
        char op;
        scanf(" %c", &op); // 读取操作
        if (op == 'H') {
            int x;
            scanf("%d", &x); // 读取插入的数据
            add_to_head(x);
        } else if (op == 'I') {
            int k, x;
            scanf("%d%d", &k, &x); // 读取插入的位置和数据
            add(k - 1, x);
        } else if (op == 'D') {
            int k;
            scanf("%d", &k); // 读取删除的位置
            if (k == 0) head = ne[head]; // 删除头结点
            else remove(k - 1);
        }
    }
    for (int i = head; i != -1; i = ne[i]) {
        printf("%d ", e[i]); // 使用printf加快输出
    }
    printf("\n");
    return 0;
}

双链表

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100010;
int e[N],l[N],r[N],idx;

//初始化
void init()
{
    r[0]=1;
    l[1]=0;
    idx=2;
}


//在结点k的右边插入一个数x
void insert(int k,int x)
{
    e[idx]=x;
    r[idx]=r[k];
    l[idx]=k;
    l[r[k]]=idx;
    r[k]=idx++;
}

void remove(int k)
{
    l[r[k]]=l[k];
    r[l[k]]=r[k];
}

int main()
{
    int m;cin>>m;
    init();
    while (m -- ){
        string op;cin>>op;
        int k,x;
        if(op=="L"){
            cin>>x;
            insert(0,x);
        }
        else if(op=="R"){
            cin>>x;insert(l[1],x);
        }
        else if(op=="D"){
            cin>>k;remove(k+1);
        }
        else if(op=="IL")//在第k个位置的左侧插入一个数
        {
            cin>>k>>x;
            insert(l[k+1],x);
        }
        else if(op=="IR")
        {
            cin>>k>>x;
            insert(k+1,x);
        }
        
    }
    for(int i=r[0];i!=1;i=r[i]){
        cout<<e[i]<<" ";
    }
    cout<<endl;
    
    return 0;
}

栈和队列

单调栈

#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;

int main()
{
    int n;cin>>n;
    while (n -- ){
        int x;cin>>x;
        while(tt&&stk[tt]>=x)tt--;
        if(tt!=0)cout<<stk[tt]<<" ";
        else cout << "-1"<<" ";
        
        stk[++tt]=x;
    }
    return 0;
}

【模板】单调栈 - 洛谷

逆序处理但是下标不变

#include <iostream>
using namespace std;
const int N = 3e6+10;
int stk[N], tt;
int a[N],b[N];

int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    for(int i=n;i>0;i--)
    {
        while(tt&&a[stk[tt]]<=a[i])tt--;
        b[i]=stk[tt];
        stk[++tt]=i;
    }
    
    for(int i=1;i<=n;i++)cout<<b[i]<<" ";
    
    return 0;
}

 

单调队列(滑动窗口) 

活动 - AcWing

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e6+10;

int a[N];
int hh=1,tt=0;
int n,k;
int main()
{
    cin>>n>>k;
    
    for(int i=1;i<=n;i++)cin>>a[i];
    
    int q1[N];
    for(int i=1;i<=n;i++){
        while(hh<=tt&&a[q1[tt]]>a[i])tt--;
        q1[++tt]=i;
        if(q1[hh]<i-k+1)hh++;
        if(i>=k)printf("%d ",a[q1[hh]]);
    }
    cout<<endl;
    
    //清空q
    int q2[N];
    for(int i=1;i<=n;i++){
    while(hh<=tt&&a[q2[tt]]<a[i])tt--;
    q2[++tt]=i;
    if(q2[hh]<i-k+1)hh++;
    if(i>=k)printf("%d ",a[q2[hh]]);
    }
    
    
    return 0;
}

int hh=1,tt=0;
for(int i=1;i<=n;i++){
    while(hh<=tt&&a[q[tt]]>=a[i])tt--;//队尾出队(队列不为空且新元素更优)
    q[++tt]=i;//队尾入队
    if(q[hh]<i-k+1)hh++;
    if(i>=k)printf("%d ",a[q[hh]]);//输出最值(队头)

 并查集

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=1e5+10;
int n,m;
int p[N];

int find(int x)
{
    if(p[x]!=x)p[x]=find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)p[i]=i;
    while(m--)
    {
        char op;
        int a,b;
        cin>>op>>a>>b;
        if(op=='M')
        {
            //find找这个东西所在的编号
            p[find(a)]=find(p[b]);
        }
        if(op=='Q')
        {
            if(find(a)==find(b))
            {
                cout<<"Yes"<<endl;
            }
            else 
            {
                cout<<"No"<<endl;
            }
        }
        
    }

    
    return 0;
}

相关推荐

  1. 算法 | 日记

    2024-07-11 19:44:02       23 阅读
  2. 「优选算法」:无重复字符的最长子串

    2024-07-11 19:44:02       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 19:44:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 19:44:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 19:44:02       57 阅读
  4. Python语言-面向对象

    2024-07-11 19:44:02       68 阅读

热门阅读

  1. xss攻击

    2024-07-11 19:44:02       23 阅读
  2. Rust简明教程第六章-错误处理&生命周期

    2024-07-11 19:44:02       26 阅读
  3. 【Django】Django 使用连接串配置数据库

    2024-07-11 19:44:02       22 阅读
  4. Sass 和 SCSS

    2024-07-11 19:44:02       19 阅读
  5. 系统迁移从CentOS7.9到Rocky8.9

    2024-07-11 19:44:02       23 阅读
  6. 深入理解CSS中的块格式化上下文(BFC)

    2024-07-11 19:44:02       21 阅读
  7. EdgeOne安全能力开箱测评挑战赛

    2024-07-11 19:44:02       24 阅读
  8. mysql 8.0.37 客户端在centos7安装顺序

    2024-07-11 19:44:02       22 阅读
  9. 【C++】include头文件中双引号和尖括号的区别

    2024-07-11 19:44:02       17 阅读
  10. 在 MyBatis-Plus 中,字段更新为 null 的方法

    2024-07-11 19:44:02       17 阅读
  11. html基础-持续更新

    2024-07-11 19:44:02       23 阅读