题目描述

丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到 n 编号。每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0~k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。

两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过 p 。

他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 p 元的咖啡店小聚。

分析

很明显维护两个颜色相同的区间最小值,取每次取min判断是否不超过p即可.

一 :O(n^3)做法,就是暴力嘛 emmm 略过了

二 :O(假的n^3)做法,时间复杂度并不会证明

数组last记录每个位置i的上一个相同颜色的位置
数组head[color]记录颜色color最后一次出现的位置
记录完之后就类似链式前向星地跑就可以了

吸氧之后可以70pts

不吸氧的话60pts

代码:

#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 200008
#define ls o<<1
#define rs o<<1|1
IL void read(int &x){
int f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,k,p,ans;
int ST[N][21];
int head[N],last[N];
//k为色调数目,p为最低最多能花的钱.
struct STbiao
{
IL void pre()
{
for(RI j=1;(1<<j)<=n;j++)
for(RI i=1;i+(1<<j)-1<=n;i++)
ST[i][j]=std::min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
IL int query(int l,int r)
{
int k=log2(r-l+1);
return std::min(ST[l][k],ST[r-(1<<k)+1][k]);
}
}st;
int main()
{
read(n),read(k),read(p);
for(RI i=1,col;i<=n;i++)
{
read(col),read(ST[i][0]);
last[i]=head[col];
head[col]=i;
}
st.pre();
for(RI c=0;c<k;c++)
for(RI i=head[c];i;i=last[i])
for(RI j=last[i];j;j=last[j])
if(st.query(j,i)<=p)ans++;
printf("%d",ans);
}

三 考虑优化ST

优化思想借鉴于 @ShawnZhou

我们可以再维护两个数组pre和cnt

pre[i]数组记录到当前位置颜色为i的价值小于等于p的客栈个数
cnt[i]数组记录到当前位置颜色i出现次数

因此我们可以减少枚举次数,从而达到优化时间的目的。

-----------------AC代码-----------------

#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 200008
#define ls o<<1
#define rs o<<1|1
IL void read(int &x){
int f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,k,p,ans;
int ST[N][21];
int head[N],last[N],color[N],cnt[N],pre[N];
//k为色调数目,p为最低最多能花的钱.
struct STbiao
{
IL void pre()
{
for(RI j=1;(1<<j)<=n;j++)
for(RI i=1;i+(1<<j)-1<=n;i++)
ST[i][j]=std::min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
IL int query(int l,int r)
{
int k=log2(r-l+1);
return std::min(ST[l][k],ST[r-(1<<k)+1][k]);
}
}st;
int main()
{
read(n),read(k),read(p);
for(RI i=1,col;i<=n;i++)
read(color[i]),read(ST[i][0]);
st.pre();
for(RI i=1;i<=n;i++)
{
if(!head[color[i]])
{
cnt[color[i]]++;
head[color[i]]=i;
}
else
{
if(st.query(head[color[i]],i)<=p)
ans+=cnt[color[i]],pre[color[i]]=cnt[color[i]];
//如果当前位置与上一颜色相同位置之间有任意一家客栈的花费小于等于p
//那么我们就可以选择当前位置的客栈与更之前位置的客栈
//并更新可以对答案贡献的数组.
else
ans+=pre[color[i]];
cnt[color[i]]++;head[color[i]]=i;
}
}//这一层for即为优化后的,其他位置并没有改动。
printf("%d",ans);
}

ST表【p1311】 选择客栈的更多相关文章

  1. 洛谷 P1311 选择客栈 解题报告

    P1311 选择客栈 题目描述 丽江河边有 \(n\) 家很有特色的客栈,客栈按照其位置顺序从 \(1\) 到 \(n\) 编号.每家客栈都按照某一种色调进行装饰(总共 \(k\) 种,用整数 \(0 ...

  2. 洛谷P1311 选择客栈

    P1311 选择客栈 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一 ...

  3. Luogu P1311 选择客栈(前缀和)

    P1311 选择客栈 题意 题目描述 丽江河边有\(n\)家很有特色的客栈,客栈按照其位置顺序从\(1\)到\(n\)编号.每家客栈都按照某一种色调进行装饰(总共\(k\)种,用整数\(0\)~\(k ...

  4. 【洛谷】【st表+模拟】P1311 选择客栈

    [题目描述:] 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖 ...

  5. P1311 选择客栈[模拟]

    题目描述 丽江河边有nn家很有特色的客栈,客栈按照其位置顺序从 11到nn编号.每家客栈都按照某一种色调进行装饰(总共 kk 种,用整数 00 ~k-1k−1 表示),且每家客栈都设有一家咖啡店,每家 ...

  6. [NOIP2011] 提高组 洛谷P1311 选择客栈

    题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均 ...

  7. 洛谷 P1311 选择客栈

    题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均 ...

  8. 2011 luogu P1311 选择客栈

    题目描述 丽江河边有 nn 家很有特色的客栈,客栈按照其位置顺序从 1 到 n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖 ...

  9. 洛谷 P1311 选择客栈 —— 水题

    题目:https://www.luogu.org/problemnew/show/P1311 看每个位置能否成为咖啡店,然后作为客栈和前面配对即可. 代码如下: #include<iostrea ...

  10. 洛谷——P1311 选择客栈

    https://www.luogu.org/problem/show?pid=1311 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰 ...

随机推荐

  1. iOS笔记056 - UI总结02

    九宫格布局 UICollectionViewController 创建控制器一定要指定默认的布局样式. // 加载一个九宫格布局的控制器,必须指定布局样式 UICollectionViewFlowLa ...

  2. 什么是 IRC?

    IRC是Internet Relay Chat 的英文缩写,中文一般称为互联网中继聊天.它是由芬兰人Jarkko Oikarinen于1988年首创的一种网络聊天协议.经过十年的发展,目前世界上有超过 ...

  3. 每天一个Linux命令(3):ls命令

    ls命令用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. 语法 ls(选项)(参数) 选项 -a:显示所有档案及目录(ls内定将档案名 ...

  4. 哲学家就餐-同步问题解析-python

    五个哲学家吃五盘通心粉,由于通心粉很滑,所以必须要拿起左右两边的叉子才能吃到. 叉子的摆放如图所示. 那么问题来了:能为每一个哲学家写一段描述其行为的程序,保证不会出现死锁. 解法1:让他等待能够使用 ...

  5. win10 64位 C# 连接oracle 32位, 遇到的问题及解决

    首次 本机电脑是win10系统 64位的:安装的oracle数据库也是64位的: 服务器端的oracle 是32位的: 第一次安装的pl/sql 也是64位的, 配置完  F:\app\ln_qi\p ...

  6. 指定user镜像安装的磁盘

    ironic node-update <node uuid> add properties/root_device='{"name":"/dev/sdb&qu ...

  7. linux 出错 “INFO: task xxxxxx: 634 blocked for more than 120 seconds.”的3种解决方案(转)

    linux 出错 “INFO: task xxxxxx: 634 blocked for more than 120 seconds.”的3种解决方案 1 问题描述 服务器内存满了,ssh登录失败 , ...

  8. shell之route命令相关

    使用下面的 route 命令可以查看 Linux 内核路由表. # route Destination Gateway Genmask Flags Metric Ref Use Iface 192.1 ...

  9. 剑指offer:二维数组中的查找

    目录 题目 解题思路 具体代码 题目 题目链接 剑指offer:二维数组中的查找 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺 ...

  10. [poj] 1269 [zoj] 1280 Interesting Lines || 求两直线交点

    POJ原题 ZOJ原题 多组数据.每次给出四个点,前两个点确定一条直线,后两个点确定一条直线,若平行则输出"NONE",重合输出"LINE",相交输出" ...