CF802C Heidi and Library (hard)
模拟退火。
最初的方案是每买一本书就马上扔掉,花费 \(\sum c_{a_i}\)。然后问题转化成保留一些书,最大化价值。
考虑 \(i\) 不需要买的情况,当且仅当前一个和它颜色相同的书没有被扔掉,设前一个颜色相同的是 \(la_{a_i}\),那么在时间 \([la_{a_i},i)\) 中,第 \(la_{a_i}\) 本书会一直在书架上面。
因此问题就是有 \(O(n)\) 个区间,最大化选择的区间价值,使得每个时间被覆盖的次数不超过 \(m-1\)(不是 \(m\),因为每个时间你需要一个空的位置来买书以及马上扔掉)。
这个非常的网络流,但是我不会建模。。。
于是可以模拟退火。给所有区间钦定一个选择顺序,然后按顺序贪心地选择,如果能选就直接选上。(一次贪心可以使用线段树优化,\(O(n \log n)\))显然这个贪心是错误的,所以每次退火随机交换两个顺序,卡个时间一直做退火。
可以过。
// sa yyds!
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace plastic {constexpr int N=85;int n,a[N],c[N],m;ll ans;struct edge {int l,r,w;};vector<edge> vec;int la[N];bool del[N];int s;constexpr double time_limit=0.95,T=10,delta=0.99,eps=1e-15;mt19937 rd(random_device{}());ll mx;struct seg {int tr[N<<2],tag[N<<2];void clear() { memset(tr,0,sizeof(tr)), memset(tag,0,sizeof(tag)); }void maketag(int u,int t) {tr[u]+=t,tag[u]+=t;}void pushup(int u) { tr[u]=max(tr[u<<1],tr[u<<1|1]); }void pushdown(int u) { if(tag[u]) maketag(u<<1,tag[u]),maketag(u<<1|1,tag[u]), tag[u]=0;}void insert(int u,int l,int r,int L,int R) {if(l>=L&&r<=R) return maketag(u,1), void(0);int mid=(l+r)>>1;pushdown(u);if(L<=mid) insert(u<<1,l,mid,L,R);if(mid+1<=R) insert(u<<1|1,mid+1,r,L,R);pushup(u);}int query(int u,int l,int r,int L,int R) {if(l>=L&&r<=R) return tr[u];int mid=(l+r)>>1;pushdown(u);int s=0;if(L<=mid) s=query(u<<1,l,mid,L,R);if(mid+1<=R) s=max(s,query(u<<1|1,mid+1,r,L,R));pushup(u);return s;}}Tr;ll calc() {ll sum=0;Tr.clear();for(auto u : vec) {if(u.l+1<=u.r-1) {if(Tr.query(1,1,n,u.l+1,u.r-1)<=m-2) sum+=u.w, Tr.insert(1,1,n,u.l+1,u.r-1);} else sum+=u.w;}return sum;}void sa() {double t=T;while(t>eps) {int x=rd()%s,y=rd()%s;swap(vec[x],vec[y]);ll now=calc();if(now > mx) mx=now;else if(1.0*(mx-now)*T>rand()/RAND_MAX) swap(vec[x],vec[y]);t*=delta;}}void main() {clock_t st=clock();srand(time(0));sf("%d%d",&n,&m);rep(i,1,n) sf("%d",&a[i]);rep(i,1,n) sf("%d",&c[i]);rep(i,1,n) {ans+=c[a[i]];if(la[a[i]]) vec.push_back({la[a[i]],i,c[a[i]]});la[a[i]]=i;}s=vec.size();while(clock()-st<time_limit*CLOCKS_PER_SEC) sa();pf("%lld\n",ans-mx);}
}
int main() {plastic :: main();
}