题解:P13504 [OOI 2024] More Gifts
SunburstFan · · 题解
OOI 超级无敌强强题。
不难发现,如果初始序列中的元素种类本身就只有
如果原序列中有大于
我们可以把两个序列
注意到
我们考虑维护
这个东西可以用滑动窗口维护。
计算出
进入循环节前最多走
整个算法的瓶颈在于离散化,总体时间复杂度
代码:
void solve(){
cin>>n>>k>>t;
for(int i=1;i<=n;i++) cin>>a[i];
// 离散化 a
vector<ll> vec;
for(int i=1;i<=n;i++) vec.push_back(a[i]);
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(int i=1;i<=n;i++) a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin()+1;
int m=vec.size(); // 种类
if(vec.size()<=t) return cout<<1<<'\n',void();
for(int i=1;i<=n;i++) a[n+i]=a[i];
for(int i=0;i<=m;i++) cnt[i]=0;
int cur=0,r=1;
for(int l=1;l<=n;l++){
while(r<=2*n){
if(cnt[a[r]]==0){
if(cur==t) break;
cur++;
}
cnt[a[r]]++,r++;
}
jump[l]=r-l;
cnt[a[l]]--;
if(cnt[a[l]]==0) cur--;
}
ll tot=n*k,cur_dis=0;
vector<pii> vis(n+1,{-1,-1});
ll ans=0,u=1;
while(cur_dis<tot){
if(vis[u].fi!=-1){
ll cyc_lenseg=ans-vis[u].fi,cyc_lendis=cur_dis-vis[u].se;
ll rem=tot-cur_dis,loops=rem/cyc_lendis;
if(loops>0){
ans+=loops*cyc_lenseg;
cur_dis+=loops*cyc_lendis;
fill(vis.begin(),vis.end(),make_pair(-1,-1));
continue;
}
}
vis[u]={ans,cur_dis};
ll step=jump[u];
cur_dis+=step;
ans++;
u=(u+step-1)%n+1;
}
return cout<<ans<<'\n',void();
}