CF18D
设 \(f_i\) 表示前 \(i\) 个事件发生后的最大收益,如果第 \(i\) 个事件是获得硬盘,则 \(f_i \leftarrow f_{i-1}\),否则二分找到最大的 \(j\) 使第 \(j\) 个事件得到的硬盘与当前需要的相同(尽可能减少对前面的影响。可以预处理每种硬盘对应的事件编号),则 \(f_i\leftarrow \max (f_j+2^x,f_{i-1})\)。实现时需要高精度,可以开结构体重载运算符以简化代码。
实测发现不需要二分查找 \(j\),直接暴力找也能通过,而且时空几乎一样。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> G[2010];
struct N{
int a[1010];
N(){
memset(a,0,sizeof(a));
a[0]=1;
}
N operator+(const N &A)const{
N B;
for(int i=1;i<=max(a[0],A.a[0]);i++){
B.a[i]+=a[i]+A.a[i];
B.a[i+1]+=B.a[i]/10;
B.a[i]%=10;
}
B.a[0]=max(a[0],A.a[0]);
if(B.a[B.a[0]+1])B.a[0]++;
return B;
}
}p[2010],f[5010],ans;
N mx(N A,N B){
if(A.a[0]!=B.a[0]){
if(A.a[0]>B.a[0])return A;
return B;
}
for(int i=A.a[0];i>=1;i--){
if(A.a[i]>B.a[i])return A;
if(A.a[i]<B.a[i])return B;
}
return A;
}
string s;
int n,op[5010],x[5010];
int main(){
p[0].a[1]=1;
for(int i=1;i<=2000;i++)
p[i]=p[i-1]+p[i-1];
cin>>n;
for(int i=1;i<=n;i++){
cin>>s>>x[i];
if(s=="win")op[i]=1,G[x[i]].push_back(i);
else op[i]=2;
}
for(int i=1;i<=n;i++){
f[i]=f[i-1];
if(op[i]==2){
if(!G[x[i]].size())continue;
if(G[x[i]][0]>i)continue;
auto it=upper_bound(G[x[i]].begin(),G[x[i]].end(),i);
it--;
int j=*it;
f[i]=mx(f[i],f[j]+p[x[i]]);
ans=mx(ans,f[i]);
}
}
for(int i=ans.a[0];i>=1;i--)
cout<<ans.a[i];
return 0;
}

浙公网安备 33010602011771号