题意
在数轴上有 \(n\) 块宝石,当你走到一个点时,可以获得点上所有的宝石。
若前一步走了 \(c\) 个单位长度,那么下一步可以走 \(c-1,c,c+1\) 个单位长度。
你最开始在原点,可以向右走 \(d\) 个单位长度,求最多可获得多少宝石。
分析
设 \(f_{i,j}\) 表示在第 \(i\) 个点,上一步走 \(j\) 个单位长度可获得的最大宝石数。
但是 \(n,p_i\) 的范围是 \(3\times 10^4\),二维数组会 MLE,考虑怎么优化。
因为最远的宝石在 \(3\times 10^4\),设步数变化 \(x\) 次,则最大的 \(x\) 满足 \(\frac{(2d+x)(x+1)}{2}\le 3\times 10^4\),解得 \(x\) 不会超过 \(300\)。
更改一下状态,设 \(f_{i,j}\) 表示在第 \(i\) 个点,\(d\) 变化了 \(j\) 次所能得到的最大宝石数。
总时间复杂度 \(O(300n)\)。
Code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
const ll maxn=30000,inf=400;
ll n,d,f[maxn+5][inf*2+5],cnt[maxn+5],ans;
signed main(){
n=read(),d=read();
for(ll i=1;i<=n;++i)++cnt[read()];
for(ll i=0;i<=maxn;++i){
for(ll j=-inf;j<=inf;++j){
f[i][inf+j]=LLONG_MIN;
}
}
f[d][inf]=cnt[0]+cnt[d];
for(ll i=d;i<=maxn;++i){
for(ll j=-inf;j<=inf;++j){
if(f[i][inf+j]==LLONG_MIN)continue;
for(ll k=-1;k<=1;++k){
ll len=d+j+k;
if(j+k<-inf||j+k>inf||len<1||i+len>maxn)continue;
f[i+len][inf+j+k]=max(f[i+len][inf+j+k],f[i][inf+j]+cnt[i+len]);
}
}
}
for(ll i=0;i<=maxn;++i){
for(ll j=-inf;j<=inf;++j){
ans=max(ans,f[i][inf+j]);
}
}
printf("%lld",ans);
return 0;
}
标签:10,宝石,ll,Treasure,Hunter,len,times,CF505C,inf
From: https://www.cnblogs.com/run-away/p/18089590