题解:P13535 [IOI 2025] 纪念品(souvenirs)
有意思的题目。但是不难,因为这题的约束太强了,导致你在每种情况下基本只能进行一种操作(有一些可能合法但是显然无意义的操作就不去考虑了),所以顺着这个模拟就可以 AC 了!
记 solve(i,M) 表示已知
你会发现初始为了去求
假设返回了
于是直接询问
于是可以将上述问题
下面分析使用购买次数的问题,要求购买
这个问题就完美解决了。
#include<bits/stdc++.h>
#define pb emplace_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef vector<int> vi;
const int maxn=110;
int n,cnt[maxn]; ll co[maxn];
pair<vi,ll> transaction(ll M);
void to(ll M);
void calc(pair<vi,ll> vec,ll M){
vi id=vec.fi,tmp; M-=vec.se;
for(auto z:id)
if(co[z]) M-=co[z];
else tmp.pb(z);
id.clear(); for(auto z:tmp) id.pb(z);
while(id.size()>1){
to(M/id.size());
while(co[id.back()]) M-=co[id.back()],id.pop_back();
}
co[id.front()]=M;
}
void solve(int pos,ll M,pair<vi,ll> vec){
for(auto id:vec.fi) cnt[id]--;
if(!co[pos]) calc(vec,M);
while(co[pos+1]&&pos+1<=n) pos++;
if(pos<n) to(co[pos]-1);
}
void to(ll M){
pair<vi,ll> res=transaction(M);
solve(res.fi.front(),M,res);
}
void buy_souvenirs(int N,ll P0){
memset(co,0,sizeof(co));
for(int i=1;i<=N-1;i++) cnt[i]=i;
n=N-1; to(P0-1);
for(int i=1;i<=n;i++)
while(cnt[i]--) transaction(co[i]);
}