题解:P10647 [NordicOI 2023] Ice Cream Machines
AuCodingFrogHoward · · 题解
题解:P10647 [NordicOI 2023] Ice Cream Machines
题目传送门
引入
首先,我们想要暴力拿 79 分再进行火车头优化,不难想象暴力程序:
码1
用队列处理位置,类似于广搜的思路进行枚举,安排每个机子何时使用,但是时间复杂度劣,为
#include<bits/stdc++.h>
using namespace std;
const int MAXN=200005;
int m,k,n,ans=0;
queue<int> pos[MAXN];//使用队列存储冰激凌机子的口味
bool has[MAXN];
int mac[MAXN],use=0;
int ice[MAXN],where;
void an_pai(int x)
{
pos[x].pop();//依次弹出判断
if(!has[x])
{
ans++;
if(use<k)
{
mac[++use]=x;
has[x]=true;
return;
}
//下面是判断此冰激凌机以后是否使用
int far=0,bes;
for(int i=1;i<=use;i++)
{
if(pos[mac[i]].empty())
{
has[mac[i]]=false;
has[x]=true;
mac[i]=x;
return;
}
else if(far<pos[mac[i]].front()) far=pos[mac[i]].front(),bes=i;
}
has[mac[bes]]=false;
mac[bes]=x;
has[x]=true;
//不处理
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);//输入
for (int i=1,x;i<=n;i++)
{
scanf("%d",&x);
pos[x].push(i);//压入队列
ice[i]=x;//初始化
}
for(where=1;where<=n;where++) an_pai(ice[where]);//依次判断每个冰激凌机
printf("%d",ans);
return 0;
}
鸣谢: @un1i 指导
优化
看范围,
我们不甘落后,看着堆的标签,灵光一闪,想出
可以用大根堆处理时限,把编号和征用时间压进堆中,进行排序:征用时间靠后者优先,就减少了用于排序的时间复杂度,是一个较好的优化。
码2
有 28 分 WA 代码(sbtk7 AC):
#include<iostream>
#include<queue>
#define int long long
#define ctn continue
#define I ios::sync_with_stdio(0);
#define AK cin.tie(0);
#define CSP cout.tie(0);
#define endl "\n"
using namespace std;
struct node//定义结构体小根堆
{
int a1,b1;
friend bool operator<(node a,node b)//判断函数
{
if(a.a1!=b.a1) return a.a1<b.a1;
return a.b1<b.b1;
}
};
priority_queue<node> q;//优先队列
int c[200005],position[200005],xia[200005];
int counter,answer;
bool have[200005];
int n,m,k;
inline void input()//不那么快的快读
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
xia[i]=n+1;
cin>>c[i];
}
}
inline node mp(int x,int y)//不想make_pair
{
node zc;
zc.a1=x,zc.b1=y;
return zc;
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
I AK CSP
input();
for(int i=1;i<=n;i++)
{
xia[position[c[i]]]=position[c[i]]=i;//初始化
}
for(int i=1;i<=n;i++)
{
if(have[c[i]])
{
q.push(mp(xia[i],c[i]));
ctn;
}
if(counter==k)
{
int linshi=q.top().b1;
have[linshi]=false;
q.pop();
counter-=1;
}
q.push(mp(xia[i],c[i]));//压入堆逐个处理,类似于程序 1
have[c[i]]=true;
counter++,answer++;
}
cout<<answer<<endl;
return 0;
}
我们充分发扬人类智慧,使用嫁接之术,特判数据范围,
码3
100 分代码应运而生:
#include<bits/stdc++.h>
#define ctn continue
#define I ios::sync_with_stdio(0);
#define AK cin.tie(0);
#define CSP cout.tie(0);
#define endl "\n"
#define MAXN 200005
using namespace std;
int m,k,n,ans=0;
queue<int> pos[MAXN];
bool has[MAXN];
int mac[MAXN],use=0;
int ice[MAXN],where;
struct node
{
int a1,b1;
friend bool operator<(node a,node b)
{
if(a.a1!=b.a1) return a.a1<b.a1;
return a.b1<b.b1;
}
};
priority_queue<node> q;
int c[200005],position[200005],xia[200005];
int counter,answer;
bool have[200005];
inline node mp(int x,int y)
{
node zc;
zc.a1=x,zc.b1=y;
return zc;
}
void an_pai(int x)
{
pos[x].pop();
if(!has[x])
{
ans++;
if(use<k)
{
mac[++use] = x;
has[x]=true;
return;
}
int far=0,bes;
for(int i=1;i<=use;i++)
{
if(pos[mac[i]].empty())
{
has[mac[i]]=false;
has[x]=true;
mac[i]=x;
return;
}
else if(far<pos[mac[i]].front()) far=pos[mac[i]].front(),bes=i;
}
has[mac[bes]]=false;
mac[bes]=x;
has[x]=true;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
if(k<=100)
{
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
pos[x].push(i);
ice[i]=x;
}
for(where=1;where<=n;where++) an_pai(ice[where]);
printf("%d",ans);
return 0;
}
else
{
I AK CSP
for(int i=1;i<=n;i++)
{
xia[i]=n+1;
cin>>c[i];
}
for(int i=1;i<=n;i++)
{
xia[position[c[i]]]=position[c[i]]=i;
}
for(int i=1;i<=n;i++)
{
if(have[c[i]])
{
q.push(mp(xia[i],c[i]));
ctn;
}
if(counter==k)
{
int linshi=q.top().b1;
have[linshi]=false;
q.pop();
counter-=1;
}
q.push(mp(xia[i],c[i]));
have[c[i]]=true;
counter++,answer++;
}
cout<<answer<<endl;
return 0;
}
}
总结
综上,本篇题解的思维瓶颈和妙处在于人类智慧之嫁接堆优化贪心的策略,减小时间复杂度,防止 TLE 。
望理解望通过 qwq