vj第一场

未完待续
第一场:
主要有三道 思维题 得到经验 对于看上去很复杂的题目 其实 在某种 程度上很可能就是 关于思维或者是数学方面的找规律题目 应该耐下心来 慢慢找

再就是 一到对于超时问题的优化 可以用set代替 数组的遍历 从而节省 时间 以及lower_bound 和 upper_bound 两种函数 在set中寻找目标的值写法 不只可以单单应用在数组中 还有就是 通过这道题目 也可以用 优先队列的方法进行解答 应该给予相应的重视与学习

下面要学习的相关算法:
1.数据的离散化 这个已经用到很多了 学习一下
2.最短路和最小生成树算法的学习 主要最短路再学习flyod算法和最小生成树再了解 迪杰斯特拉算法 加上 优先队列的 的优化算法
3.线段树对于最小子区间和的维护 以及要复习 线段树其他的相关操作

补题任务
F J L先完成这三道

F:
cnt大小的不断变化 代表着不同类型的消息 他们数的大小也就是他们产生的先后顺序 每一个数就代表着是一个消息

对应着三种操作
1:编号为x的应用生成一条未读消息
2:吧编号为x的应用所有的消息标记为已读 不管是否已经有读过的消息
3:把前t条消息标记为已读

进行完每一次操作后 输出当前手机上所有应用 未读的消息总数是多少
用 vector 和 set 这两个stl函数 来完成

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>

using namespace std;
typedef long long ll;
const int N = 3e5 + 7;
// 要学会 用 vector数组 来存放有关系 两个量 一个应用 可能生成不同的消息因此用 vector搞定
vector<int>app[N];// 用来记录某个应用 生成的 消息总数
set<int>num;// 数量

int n,q,x,t,cnt;// 这里用 cnt一变化 一个数便代表着一种类型的数

int main()
{
    while(scanf("%d%d",&n,&q) != EOF)
    {
        cnt = 0;// 也代表着消息的类型
        num.clear();
        int pos = 0;
        //scanf("%d%d",&t,&x);
        for(int i = 1;i <= q;i ++)
        {
            scanf("%d%d",&t,&x);
            if(t == 1)
            {
                app[x].push_back(++cnt);
                num.insert(cnt);// 这集合代表的是 消息的个数
            }
            else if(t == 2)
            {
                for(int i = 0;i < app[x].size();i ++)
                {
                    num.erase(app[x][i]);// 把这些元素从集合从集合中删去
                }
                app[x].clear();// 向量数组直接清空即可
            }
            else
            {
                for(int i = pos;i <= x;i ++)
                {
                    num.erase(i);
                }
                pos = max(pos,x);// 这个操作可避免 如果第一次 删了前五条 下一次要删前三条的话 就 不用再删了 避免了重复操作
            }
            printf("%d\n",num.size());
        }
    }
    return 0;
}

J:经典  二维前缀和  差分
先确定一下什么是二维前缀和
一维前缀和就是 给定区间【L,R】求解区间中的元素的和是多少 只需要用数组 这么存数据即可
a[i] += a[i-1];这样数组记录的就是 以给定数值为结尾的 一段数据的和 
ans =  a[r] - a[l-1];即可实现

自然的二维前缀和 也可以如此的表示

int mp[17][17];
for(int i = 1;i <= n;i ++)
{
    for(int j = 1;j <= m;j++)
    {
        scanf("%d",&mp[i][j]);
        mp[i][j] +=  mp[i][j-1] + mp[i-1][j] - mp[i-1][j-1];// 这就是 求解代码 也就是求解矩形的面积的大小的代码
    }
    int ans = 0;
    scanf("%d%d%d%d",&x1&y1&x2&y2);
    ans = mp[x2][y2] - mp[x2-1][y2] - mp[x2][y2-1] + mp[x1][y];//求解二维前缀和的代码
}

差分: 是对于区间进行一个操作  
然后在查询一个区间的和为多少 
是基于 前缀和的基础上 在增肌一个数组 来实现的
对于一维的差分
int main()
{
    int a[107];int b[107];
    // 一维的差分
    // 如果对于每次操作 我都 把 区间内的每个元素 加上一个数值 那么 肯定会超市 所以
    // 引入另一个数组 b
    int l,r,q,t;
    scanf("%d%d%d%d",&l,&r,&t,&q);
    if(t == 1)// 代表着 对区间进行 加上q的操作
    {
        b[l] += q;
        b[r+1] -= q;// 这里为什么要减去q 因为我们求的是 前缀和 后面的数会加上前面的加上的q
        // 但实际上 我们只对 l到r区间内的数加上了q 而 r之后的数如果不减去 那么最后也会加上一个q
    }
    else if(t == 2)
    {
        b[l] -= q;
        b[r+1] += q;// 与加同理
    }
    int add = 0;
    for(int i = 1;i <= n;i ++)
    {
        add += b[i];// 因为有多次操作 要把每次操作的累积下来 加到后面去
        a[i] += a[i-1] + add;
    }
    return 0;
}

二维的差分:

int main()
{
    int mp[107][107];int b[107][107];
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= m;j ++)
        {
            scanf("%d",mp[i][j]);
            mp[i][j] += mp[i][j-1] + mp[i-1][j] - mp[i-1][j-1];
            // 二维前缀和
        }
    }
    int x1,x2,y1,y2,q;
    scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&q);
    // 二维差分
    // 把这个区间内的所有值 加上q
    b[x1][y1] += q;
    b[x1][y2 + 1] -= q;
    b[x2 + 1][y1] -= q;
    b[x2 + 1][y2 + 1] += q;

    return 0;
}

https://www.cnblogs.com/LMCC1108/p/10753451.html// 这篇讲解 配上画图 很清晰

J: 二维前缀和 + 差分

二维的差分

HDU 6514 经典的 二维前缀和 加 差分 算法
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>

using namespace std;
int main()
{
    int n,m,p,q;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        int b[n+5][m+5];
        int mp[n+5][m+5];
        memset(b,0,sizeof(b));
        memset(mp,0,sizeof(mp));
        scanf("%d",&p);
        int x1,x2,y1,y2;
        while(p--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            b[x1][y1]++;
            b[x2+1][y1]--;
            b[x1][y2+1]--;
            b[x2+1][y2+1]++;
        }
        for(int i = 1;i <= n;i ++)
        {
            for(int j = 1;j <= m;j ++)
            {
                b[i][j] += b[i][j-1] + b[i-1][j] - b[i-1][j-1];
            }
        }
        for(int i = 1;i <= n;i ++)
        {
            for(int j = 1;j <= m;j ++)
            {
                if(b[i][j])
                    b[i][j] = 1;// 因为 差分数组 可能会在一个地方 操作多次 但是 我最后要把它变成1 所以 要加上这一步 再来构造 监控好的地方
            }
        }
        for(int i = 1;i <= n;i ++)
        {
            for(int j = 1;j <= m;j ++)
            {
                mp[i][j] = b[i][j] + mp[i-1][j] + mp[i][j-1] - mp[i-1][j-1];
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int ans = mp[x2][y2] - mp[x2][y1-1] - mp[x1-1][y2] + mp[x1-1][y1-1];
            if(ans == (x2-x1+1) * (y2-y1+1))
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}
技术选型 【后端】:Java 【框架】:springboot 【前端】:vue 【JDK版本】:JDK1.8 【服务器】:tomcat7+ 【数据库】:mysql 5.7+ 项目包含前后台完整源码。 项目都经过严格调试,确保可以运行! 具体项目介绍可查看博主文章或私聊获取 助力学习实践,提升编程技能,快来获取这份宝贵的资源吧! 在当今快速发展的信息技术领域,技术选型是决定一个项目成功与否的重要因素之一。基于以下的技术栈,我们为您带来了一份完善且经过实践验证的项目资源,让您在学习和提升编程技能的道路上事半功倍。以下是该项目的技术选型和其组件的详细介绍。 在后端技术方面,我们选择了Java作为编程语言。Java以其稳健性、跨平台性和丰富的库支持,在企业级应用中处于领导地位。项目采用了流行的Spring Boot框架,这个框架以简化Java企业级开发而闻名。Spring Boot提供了简洁的配置方式、内置的嵌入式服务器支持以及强大的生态系统,使开发者能够更高效地构建和部署应用。 前端技术方面,我们使用了Vue.js,这是一个用于构建用户界面的渐进式JavaScript框架。Vue以其易上手、灵活和性能出色而受到开发者的青睐,它的组件化开发思想也有助于提高代码的复用性和可维护性。 项目的编译和运行环境选择了JDK 1.8。尽管Java已经推出了更新的版本,但JDK 1.8依旧是一种成熟且稳定的选择,广泛应用于各类项目中,确保了兼容性和稳定性。 在服务器方面,本项目部署在Tomcat 7+之上。Tomcat是Apache软件基金会下的一个开源Servlet容器,也是应用最为广泛的Java Web服务器之一。其稳定性和可靠的性能表现为Java Web应用提供了坚实的支持。 数据库方面,我们采用了MySQL 5.7+。MySQL是一种高效、可靠且使用广泛的关系型数据库管理系统,5.7版本在性能和功能上都有显著的提升。 值得一提的是,该项目包含了前后台的完整源码,并经过严格调试,确保可以顺利运行。通过项目的学习和实践,您将能更好地掌握从后端到前端的完整开发流程,提升自己的编程技能。欢迎参考博主的详细文章或私信获取更多信息,利用这一宝贵资源来推进您的技术成长之路!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值