题目
错误思路
-
这题特别要注意数据范围:
-
起初我的思路是直接暴力,首先输入每一条船的信息,然后从后往前遍历每一条船的时候,搜索
( t[i]-85400, t[i] ]
共有多少国籍的人,搜索方式是从t[i]开始往前搜索,然后直到搜索的值超出了范围,统计方式是利用algorithm
库中的set_union
函数。统计的复杂度是线性的,也就是O(ki)
,然后总的复杂度为O(85400*n*ki)
,这个最坏的时候超出了O(1e10)
,甚至到达了O(1e15)
。想碰一下运气看看数据捞不捞,果然只ac了70%,不过用到了很多stl模板
,还是值得记录下,代码如下:
#include<iostream>
#include<unordered_map>
#include<set>
#include<vector>
#include<algorithm>
#include<unordered_set>
using namespace std;
int n;
vector<int>t;
vector<int>ans;
unordered_map<int,unordered_set<int>>m;
int main(){
cin>>n;
int time,k,temp;
for(int i=0;i<n;i++){
cin>>time;
t.push_back(time);
cin>>k;
for(int j=0;j<k;j++){
cin>>temp;
m[time].insert(temp);
}
}
unordered_set<int>c;
for(int i=t.size()-1;i>=0;i--){
c.clear();
for(int j = i;(t[j]>t[i]-86400) && j>=0;j--){
set_union(c.begin(),c.end(),m[t[j]].begin(),m[t[j]].end(),inserter(c,c.begin()));
}
ans.push_back(c.size());
}
for(int i=ans.size()-1;i>=0;i--)
cout<<ans[i]<<'\n';
}
正确思路
- 类似于滑动窗口的思想,在输入的过程中维持一个大小为
85400
的滑动窗口,实现方式是队列。 - 每当输入一个新的船的信息,就不断检验
queue.front()
(也就是最先插入的元素,因为队列是先入先出的)的头部元素是否超出了范围,如果超出了范围,就区还原,同时删去相应的人的国籍的记录,如果此时某个国籍的数量变为0,则ans--
AC代码
#include<iostream>
#include<queue>
const int H = 86400;
const int K = 1e5+5;
using namespace std;
int n;
int ans;
queue<int>t;
queue<int>peo;
queue<int>nat;
int vis[K];
int main(){
cin>>n;
int tempt,tempk,tempnat;
for(int i=0;i<n;i++){
cin>>tempt>>tempk;
t.push(tempt);
peo.push(tempk);
for(int j=0;j<tempk;j++){
cin>>tempnat;
if(vis[tempnat]==0){
ans++;
vis[tempnat]++;
}
else{
vis[tempnat]++;
}
nat.push(tempnat);
}
int popt,popk,popnat;
while(t.front()+H<=tempt){
//弹出并修改ans
popt = t.front();
t.pop();
popk = peo.front();
peo.pop();
for(int j=0;j<popk;j++){
popnat = nat.front();
nat.pop();
vis[popnat]--;
if(vis[popnat]==0) ans--;
}
}
cout<<ans<<'\n';
}
}