题意
1.给定n( n ≤ 1 e 5 n\leq1e5 n≤1e5)个数列,数列中包含:时间 t t t,个数 k ( k ≤ 3 e 5 ) k(k\leq3e5) k(k≤3e5), k k k个数
2.时间 t t t依次递增
3.统计从t开始,当
(
t
x
−
t
)
<
86400
(tx-t)<86400
(tx−t)<86400时,在
x
x
x个数列中不重复的
k
k
k个数,有多少个?
(PS:tx为第x个数列中包含的时间
t
t
t)
数据规模与约定
70分: 1 ≤ n ≤ 100 , ∑ k i ≤ 100 , 1 ≤ x i , j ≤ 100 , 1 ≤ t i ≤ 86400 1 \leq n \leq 100, \sum k_i \leq 100,1 \leq x_{i,j} \leq 100,1 \leq t_i \leq 86400 1≤n≤100,∑ki≤100,1≤xi,j≤100,1≤ti≤86400
100分: 1 ≤ n ≤ 1 0 5 , ∑ k i ≤ 3 × 1 0 5 , 1 ≤ x i , j ≤ 1 0 5 , 1 ≤ t i ≤ 1 0 9 1 \leq n \leq 10^5,\sum k_i \leq 3\times 10^5, 1 \leq x_{i,j} \leq 10^5,1\leq t_i \leq 10^9 1≤n≤105,∑ki≤3×105,1≤xi,j≤105,1≤ti≤109。
70分做法
按照题意进行暴力去重即可
去重算法(桶排序去重)解释:
基础定义↓
数列a[]:1 2 1 1 3 3 3 5(PS:qc[]数组是去重数组(桶))
a[1]=1,a[2]=2,a[3]=1,a[4]=1,a[5]=3,a[6]=3,a[7]=3,a[8]=5.
qc[a[i]]++;(0<i<9,i为正整数)
运行结果↓
qc[1] qc[2] qc[3] qc[4] qc[5]
3 1 3 0 1
运行判断与最终结果↓
运行完qc[a[i]]++后只需要判断qc[i]是否为0即可
qc[1]=true,qc[2]=true,qc[3]=true,qc[4]=false,qc[5]=true;
因为有4个为true,所以答案为4(不重复的数有4个).
70分code↓
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;//x[i][j]第i数列的j个数(共有k个),t[]是记录时间t的数组
int n,k[maxn]={},vis[maxn]={},qc[maxn]={},x[1001][1001];//k[]记录个数k
long long t[maxn]={};//vis[]是标记,qc[]是处理去重用的数组
int f(int o){//标记要退出的数列
for(int i=o;i>=1;i--)
if(t[o]-t[i]<86400) vis[i]=1;//如果时间比86400秒小,就进行标记
return 0;
}
int qc2(int o){
int mx=0;
for(int i=1;i<=n;i++){
if(vis[i]==1){//如果数列i位于86400秒内,就进行去重
for(int j=1;j<=k[i];j++){
qc[x[i][j]]++;//将第k个数的个数表现在qc[k]
if(x[i][j]>mx) mx=x[i][j];//记录k个数中的最大值,方便常数查找
}
}
}
return mx;//返回最大值
}
int qc3(int r){//r代表了最右端点值,也就是k个数中的最大值
int ans=0;//ans是答案
for(int i=1;i<=r+1;i++){//r+1是因为要将最大值一起算进去
if(qc[i]!=0) ans++;//不看个数,只看有没有,以此来去重
}
memset(qc,0,sizeof(qc));//因为已经得到答案,便要将qc[]数组清零
return ans;//返回答案
}
int main(){
cin>>n;//输入总数列的个数
for(int i=1;i<=n;i++){
cin>>t[i]>>k[i];//输入时间t和个数k
for(int j=1;j<=k[i];j++){
cin>>x[i][j];//输入k个数
}
}
for(int i=1;i<=n;i++){
f(i);//进行标记,看看这个数列在不在86400秒内
cout<<qc3(qc2(i))<<endl;//输出答案
memset(vis,0,sizeof(vis));//清零标记数组,以方便下次标记
}
return 0;//程序正常结束
}
但是这种做法得不到100分
,因为有2个
原因
1.数组
开的太大
而MLE
2.时间复杂度太高
而TLE
100分做法
100分做法就需要用到STL数据结构
了
去重算法(桶排序去重)优化:
基础定义↓
数列a[]:1 2 1 1 3 3 3 5(PS:t[]数组是去重数组(桶))
a[1]=1,a[2]=2,a[3]=1,a[4]=1,a[5]=3,a[6]=3,a[7]=3,a[8]=5.
执行顺序↓
if(t[a[i]]++)是先执行了if(t[a[i]]==0) 再执行了t[a[i]]++;
反之if(++t[a[i]]==0)是先执行了t[a[i]]++后 再执行了if(t[a[i]]==0)
优化方法↓
如果if(t[a[i]]==0) 那这个数就是第一次出现,就需要记录答案
反之,则不是第一次出现,不用记录答案
因为t[a[i]]需要+1,所以完整语句是"if(t[a[i]++==0) ans++;"
100分code↓
#include <bits/stdc++.h>
using namespace std;
int n,t,k,k1,ans=0;//n:数列的个数,t:时间,k:k个数的个数,k1:k个数本身
const int maxn=1e5+5;//maxn是边界的最大值
struct SHIP{//定义一个船的结构题
int time;//船进入的时间
vector<int> people;//存储总共 k个数的容器people
};
queue<SHIP> q;//建立一个,队列q,用来存储需要的数列
int to[maxn]={0};//
int main(){
ios::sync_with_stdio(false);//开启加速cin的优化
cin.tie(0),cout.tie(0);//同上
cin>>n;//输入数列的个数
for(int i=1;i<=n;i++){
cin>>t>>k;//输入船进入的时间,以及后面 k个数的个数
SHIP ship;//定义一个SHIP类型的变量ship
ship.time=t;//将这个ship进入的时间赋值为t
for(int j=1;j<=k;j++){
cin>>k1;//输入 k个数
ship.people.push_back(k1);//将这k个数都压进ship中的容器people中
if(to[k1]++==0) ans++;//桶排序去重优化找出答案
}
q.push(ship);//将ship这个容器整个压进队列q中
while(!q.empty()){//当这个队列是非空的时侯运行
SHIP x=q.front();//定义一个SHIP类型的变量x,并将队列的队头赋值进去
if(t-x.time>=86400){//如果队头已经不在这艘船的24小时之内了
q.pop();//将队头弹出
int siz=x.people.size();//siz是(现有的 k个数)的总个数
for(int j=0;j<siz;j++){//容器,队列...都是从0开始的
if(--to[x.people[j]]==0) ans--;//进行反向去掉桶的操作
}//反过来减去桶{队头(去过重)}的人数
}else{
break;//当这个队列不能减的时候,便结束这个循环
}
}
cout<<ans<<endl;//输出答案
}
return 0;
}