jzoj 3947. 【省常中JSOI模拟】收历史作业 最长不下降子序列

Description
小W 回到了教室,可怜的他要收历史作业,但是0901 班这群不负责任的组长把作业收得乱七八糟,散得每个座位上都有作业本,小W 只好挨个去收。
0901 班的教室可以看作是一个n 行m 列的矩形,小W 在(0,0)这个格子(位于教室的左下角),教室的门在(n-1,m-1)这个格子。每次小W 可以向相邻的格子走一步,走到某个格子时,他会收完这个格子的历史作业。小W 是个很懒的人,他想走一条最短路到教室的门口,但是作业收得太少了又会引起公愤,所以他决定走一条作业收得最多的最短路线,你能帮帮他吗?

Input
第一行三个整数n,m,k。
接下来k 行,每行三个整数a,b,c,表示在(a,b)这个格子有c 本历史作业。
Output
一行一个整数,表示最多能收到的历史作业的本数。

Sample Input
2 2 2
0 0 1
1 1 1
Sample Output
2

Data Constraint
30%的数据,n,m<=30,k<=100。
70%的数据,n,m<=10^9,k<=10000。
100%的数据,1<=n,m<=10^9,1<=k<=100000,0<=c<=300,保证每对(a,b)至多出现一次。

分析:一条可行的方案,保证a[i]<=a[i+1],b[i]<=b[i+1],不需考虑都相等情况。我们把横坐标为第一关键字,纵坐标为第二关键字从小到大排序后,相当于求b的最长不下降子序列,不过每个点有一个权值。显然最长不下降子序列可以用nlogn解决,但是是权值为1的情况,我们可以把权为ci的点拆成ci个数字,这就保证了权值都为1,然后跑一个最长不下降子序列。因为ci<=300,n<=100000,单调队列开n*c可以承受。至于二分查找到一个位置插入,就把从这个位置开始,后面ci个全部覆盖掉即可,可以通过。

至于再优化,覆盖这个考虑用平衡树或其他数据结构解决。

代码:

#include <iostream>
#include <cstdio> 
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 100001

using namespace std;

int n,m,k,sum,ans,q;
int a[N],b[N],c[N];
int list[30000001]; 

void kp(int l,int r)
{
    if (l>r) return;
    int i=l; int j=r;
    int key1=a[(l+r)/2];
    int key2=b[(l+r)/2];
    int t;
    while (i<=j)
    {
        while ((a[i]<key1) || ((a[i]==key1) && (b[i]<key2))) i++;
        while ((a[j]>key1) || ((a[j]==key1) && (b[j]>key2))) j--;
        if (i<=j)
        {
            t=a[i]; a[i]=a[j]; a[j]=t;
            t=b[i]; b[i]=b[j]; b[j]=t;
            t=c[i]; c[i]=c[j]; c[j]=t;
            i++;j--;
        }
    }
    kp(i,r);
    kp(l,j);
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    fo(i,1,k)
    {
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        sum+=c[i];      
    }       
    kp(1,k);
    int t=0;
    fo(i,1,c[1])
    {
        list[++t]=b[1];
    }       
    fo(i,2,k)
    {
        if (b[i]>=list[t])
        {
            fo(j,1,c[i])
            {
                list[++t]=b[i];
            }
            ans=max(ans,t);
        }
        else
        {
            int l=1; int r=t;
            q=t;
            while (l<=r)
            {
                int mid=(l+r)/2;
                if (list[mid]>b[i])
                {
                     q=min(q,mid);
                     r=mid-1;
                }
                else l=mid+1;
            }
            fo(j,1,c[i])
            {
                list[q++]=b[i];
            }
            t=max(t,q-1);
            ans=max(ans,t); 
        }
    }
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分析报告模块和设计数据库结构,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架构以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值