「2019冬令营提高组」全连
显然的 dp
设 f[i] 表示点击第 i 个音符时的最大价值,t[i] 表示音符 i 的准备时间
那么可以枚举 1 到 i-t[i] 的所有音符,如果 j ,如果 j+t[j] 小于等于 i ,那么 f[i]=max(f[i],f[j]+t[i]*val[i])
考虑优化转移
显然如果 i 在时间 k 时可以转移,那么后面所有的时间也都能转移
考虑用树状数组维护前缀最大值,用 vector 维护时间 k 时恰好可以转移的 f
那么每次到一个位置就把可以转移的 f 插到树状数组,然后查询最大值转移
复杂度 O(nlog_n),注意 long\ long
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<vector> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e6+7; int n,t[N],val[N]; ll T[N],f[N],ans; inline void ins(int x,ll y) { while(x<=n) T[x]=max(T[x],y),x+=(x&-x); } inline ll query(int x) { ll res=0; while(x) res=max(res,T[x]),x-=(x&-x); return res; } vector <int> v[N]; int main() { freopen("fc.in","r",stdin); freopen("fc.out","w",stdout); n=read(); for(int i=1;i<=n;i++) t[i]=read(); for(int i=1;i<=n;i++) val[i]=read(); for(int i=1;i<=n;i++) { int len=v[i].size(); for(int j=0;j<len;j++) ins(v[i][j], f[v[i][j]] ); f[i]=1ll*val[i]*t[i]+ (i>t[i] ? query(i-t[i]) : 0); if(i+t[i]<=n) v[i+t[i]].push_back(i); ans=max(ans,f[i]); } printf("%lld",ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步