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;
}
posted @ 2025-09-12 08:18  FormulaOne  阅读(18)  评论(0)    收藏  举报