这道不难的题引发了我不少思考

我第一个版本是用vector嵌套vector写成的,后来发现没必要还存储那些已经超过24h的船,完全可以删除前面的船,因此把外层vector换成了deque。

即用deque存船,用vector存储船上人的国籍

然后喜提TLE,只有70分

然后把cincout换成scanfprintf,仍然TLE

把scanfprintf换成快读快写函数,仍然TLE

意识到可以把存船换成存人,遂把deque换成queue,把存了一个int时间和一个vector国籍的船类换成的只存int时间和int国籍的人类,这样deque套vector直接变成了单单一个queue,但仍然TLE

(后来意识到这三个优化全属于小打小闹,意义不大,第三个优化有点意义,但时间提升其实也不大,还多浪费了一点空间)

然后意识到我应该分析循环次数,发现外层循环循环了n次,内层循环了Ki次+2100000。n是小于100000的数,每个n总要处理不可能缩小,可是n2100000显然达到了十的十次方超时间复杂度了。内层循环的Ki一共运行了sigmaKi次,而sigmaKi是小于300000的,最开始我看错了,我以为Ki小于300000,Ki缩小不了所以才用了个2100000级别的内层运算。结果发现Ki的和才300000次,因而很明显缩小的重点就在于这个两个100000的循环了

这段分析非常重要,让我突然一直到该优化哪里,此前优化的地方都是小打小闹,要么是常数级的优化,要么是至多1~2个数量级的优化,这段分析才真正找到了症结所在。

这种分析我已经好久没做忘却了,这道题让我拾起来这种记忆。给了我三个收获,一是要认真读题,别漏看了sigma,二是写算法前先算好自己的内层循环一共会被执行多少次。三是算法TLE了先检查循环次数是否有数量级级别的大问题,没有的话在进行常数级的小优化。

为什么有两个100000级别的循环呢,因为我用b[i]存储i国籍的人有没有,我用1和0两个状态来存储有没有,而不是用数字存储有多少,这导致我让24h以前的人出队只能将b数组全部清零然后全部新统计,而不能直接在原本b数组的基础上修修改改,因为我不知道出队后b[i]==1的数据该不该归零,毕竟24h以前的人中有没有那个国籍的人我不知道。那么,只要改存数字,把粗暴地损失了信息的b[i]=1改成b[i]++,就可以存储剩下的人了,就可以让那些人出队了,出队后只要b[i]--;我就可以判断那个国籍的人到底还有没有,从而可以直接在b数组上修修改改了,就不需要再全部清零再全部重新统计了。这样就把十的五次方级别的操作直接改成了常数级别的操作。

然后另一个100000级别的循环是我每次处理一艘船的答案的时候都是直接设置一个新的ans量并初始化为0,然后遍历b数组。可是,ans也可以略加修改变成只在原本的基础上修修改改,从而直接把遍历b数组这种是的五次方级别的操作改成了常数级别的操作。

就写出来的Code-3这样AC了。我看题解中很多人都强调要按人头来存,但根据我的分析很明显我这个算法按船来存按人头来存都是不会TLE的,因为我用船来存的时候用了vector。为了证明这一点,我有写了第二份AC-Code,就是Code-4

Code-1

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <list>
using namespace std; inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline void write(int x){
if(x==0){putchar('0');return;}
int len=0,k1=x,c[10005];
if(k1<0)k1=-k1,putchar('-');
while(k1)c[len++]=k1%10+'0',k1/=10;
while(len--)putchar(c[len]);
} struct ship
{
int t;
vector<int> na;
ship(int T,vector<int> NA){t=T;na.assign(NA.begin(),NA.end());}
};
queue<ship ,list< ship > > Q;
int b[100005],n,t,k,ana;
int main()
{
Q.push(ship(0,vector<int>()));
n=read();
for(int i=1;i<=n;i++)
{
t=read();k=read();
vector<int> tna;
for(int j=1;j<=k;j++)
{
ana=read();
tna.push_back(ana);
}
for(Q.push(ship(t,tna));Q.back().t-Q.front().t>=86400;Q.pop())
for(auto p=Q.front().na.begin();p<Q.front().na.end();p++)
b[*p]--;
for(auto p=Q.back().na.begin();p<Q.back().na.end();p++)
b[*p]++;
int ans=0;
for(int j=1;j<=100000;j++)if(b[j]>0)ans++;
write(ans);putchar('\n');
}
return 0;
}

Code-2

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <list>
using namespace std; inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline void write(int x){
if(x==0){putchar('0');return;}
int len=0,k1=x,c[10005];
if(k1<0)k1=-k1,putchar('-');
while(k1)c[len++]=k1%10+'0',k1/=10;
while(len--)putchar(c[len]);
} struct p
{
int t,na;
p(int T,int NA){t=T;na=NA;}
};
queue<p> Q;
int b[100005],n,t,k,ana;
int main()
{
Q.push(p(0,0));
n=read();
for(int i=1;i<=n;i++)
{
t=read();k=read();
for(int j=1;j<=k;j++)
{
ana=read();b[ana]++;p h=Q.front();
for(Q.push(p(t,ana));t-h.t>=86400;Q.pop())
b[Q.front().na]--;
}
int ans=0;
for(int j=1;j<=100000;j++)if(b[j]>0)ans++;
write(ans);putchar('\n');
}
return 0;
}

Code3

#include <iostream>
#include <queue>
using namespace std;
struct p{int t,na; p(int T,int NA){t=T;na=NA;} };
int b[100005],n,t,k,ana,ans;
queue<p> Q;
int main()
{
Q.push(p(0,0));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&t,&k);
for(int j=1;j<=k;j++)
{
scanf("%d",&ana);
b[ana]++;
if(b[ana]==1)ans++;
for(Q.push(p(t,ana));t-Q.front().t>=86400&&!Q.empty();Q.pop())
{
b[Q.front().na]--;
if(b[Q.front().na]==0)ans--;
}
}
printf("%d\n",ans);
}
return 0;
}

Code-4

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <list>
using namespace std; struct ship
{
int t;
vector<int> na;
ship(int T,vector<int> NA){t=T;na.assign(NA.begin(),NA.end());}
};
queue<ship> Q;
int b[100005],n,t,k,ana,ans;
int main()
{
Q.push(ship(0,vector<int>()));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&t,&k);
vector<int> tna;
for(int j=1;j<=k;j++)
{
scanf("%d",&ana);
tna.push_back(ana);
}
for(Q.push(ship(t,tna));t-Q.front().t>=86400;Q.pop())
for(auto p=Q.front().na.begin();p<Q.front().na.end();p++)
{b[*p]--;if(b[*p]==0)ans--;}
for(auto p=Q.back().na.begin();p<Q.back().na.end();p++)
{b[*p]++;if(b[*p]==1)ans++;}
printf("%d",ans);
}
return 0;
}

P2058的更多相关文章

  1. 洛谷 P2058 海港 解题报告

    P2058 海港 题目描述 小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况: ...

  2. 洛谷P2058 仪仗队

    P2058 仪仗队 24通过 34提交 题目提供者shengmingkexue 标签数论(数学相关) 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 暂时没有讨论 题目描述 作为体育委员,C君 ...

  3. 洛谷 P2058 海港 题解

    P2058 海港 题目描述 小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况: ...

  4. P2058 海港

    原题链接  https://www.luogu.org/problemnew/show/P2058 这道题昨天qyf大佬刚给我们讲了一下,所以今天就把它做啦! qyf大佬的思路和我的是一样的(其实是借 ...

  5. 洛谷 P2058 海港(模拟)

    题目链接:https://www.luogu.com.cn/problem/P2058 这是一道用手写队列模拟的一道题,没有什么细节,只是注意因为数不会很大,所以直接用数作为数组下标即可,不用用map ...

  6. [P2058][NOIP2015]海港 (模拟)

    %%%ADMAN #include<cstdio> using namespace std; int n,tot,now,ans,h; ],k[],a[],sum[]; int main( ...

  7. (寒假集训)洛谷 P2058 海港

    小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况:对于第i艘到达的船,他记录了 ...

  8. 洛谷P2058 海港

    题目描述 小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况:对于第i艘到达的船 ...

  9. 洛谷——P2058 海港

    题目传送 由于于题目保证输入的ti是递增的,所以发现当我们统计完一艘船的答案后,这个答案多少会对下一艘船的答案有贡献.同时还发现如果对每个艘船都记录他的乘客在整个数据出现的所有国籍中相应出现的次数,在 ...

  10. 【HDOJ】P2058 The sum problem

    题意很简单就是给你一个N和M,让你求在1-N的那些个子序列的值等于M 首先暴力法不解释,简单超时 再仔细想一想可以想到因为1-N是一个等差数列,可以运用我们曾经学过的只是来解决 假设开始的位置为s,结 ...

随机推荐

  1. 使用 FastEndpoints 来垂直切换Web API的控制器方法

    在我们开发项目的Web API的时候,随着项目功能要求越来越多,可能我们会为控制器基类增加越来越多的基础功能,有些功能有一定的适应性,但可能在一般的子类中用不到,而随着对控制器控制要求越来越精细,那么 ...

  2. 【笔记整理】requests使用代理

    使用proxies参数传递代理信息 import requests if __name__ == '__main__': proxies = { # 这个字典的key不可以乱写,必须是http和htt ...

  3. Asp.net core Webapi 如何执行定时任务?

    前言 在计算机系统中,定时执行一些后台任务是很常见的场景,比如定时发送邮件.备份数据等等. 那么,.NET 技术如何通过编程灵活地实现项目里复杂的自定义任务呢? 如果是 Windows 生态,通常来说 ...

  4. Android本地备份功能禁用

    最近部分设备激活客户端后发现本地备份的功能被禁用了,排查原因发现: /** * Allows the device owner to enable or disable the backup serv ...

  5. 【笔记-错误】springCloud-alibaba-feign集成sentinel的启动报错

    背景 随着Spring Cloud Alibaba 2.2.0.RELEASE的发布,终于可以使用最新的Spring Boot和Spring Cloud. 现在的环境 依赖 版本 Spring Boo ...

  6. 在 Walrus 上轻松集成 OpenTofu

    OpenTofu 是什么? OpenTofu 是一个开源的基础设施即代码(IaC)框架,被提出作为 Terraform 的替代方案,并由 Linux 基金会管理.OpenTofu 的问世为应对 Has ...

  7. 一文了解Vprix容器流媒体平台和传统云桌面的区别、优劣势

    在当今数字化时代,随着云计算和远程办公的兴起,云桌面项目成为了提升工作效率和灵活性的重要工具.云桌面项目通过将用户的桌面环境和应用程序虚拟化,为用户提供了随时随地访问个人工作环境的便利.本文将介绍Vp ...

  8. Base64编码:数据传输的安全使者

    Base64编码是一种将二进制数据转换为可传输的文本表示形式的方法,它在全球范围内被广泛应用于网络通信.数据存储和传输等领域.本文将从多个方面介绍Base64编码的原理.应用及其在现实场景中的优势,帮 ...

  9. Vue源码学习(十九):router基本原理

    好家伙,   0.什么是路由? 路由就是匹配到对应路径显示对应的组件! 那么我们要如何去实现? 我们来回忆一下这router怎么用的 1. 声明式路由配置:在路由配置对象中,定义路径与组件的映射关系. ...

  10. Deployment控制器

    目录 Deployment控制器 1.deployment及副本数 使用命令生产yaml文件模板 控制器通过什么管理pod? 2.副本数修改方法 3.动态扩展HPA 4.镜像滚动升级及回滚 升级 回退 ...