题意:给你一个0到n的柱子,一开始在0,需要跳到大于n的地方,每个柱子上有个得分,
且限制了最大跳跃步数;
思路:一般很容易想到一个 n*p 时间复杂度的DP , 表示以 i 为结尾的最大得分然后枚举前p-1个位置,但是时间肯定不允许,可以想到这类题典型就是单调队列优化的;
然后每次询问又给了限制,这里就用到了调和级数,也就是 n/1+n/2+n/3+n/4+...+n/n 大概在nlogn的级别,而单调队列优化DP 又是O(N)的,这样就可以看似暴力,其实稳过的a掉了
具体细节看代码
int n, p, Q;
int a[N], q[N], f[N];
int hh, tt;
void solve()
{
cin >> n >> Q >> p;
for (int i = 1; i <= n; i++)
cin >> a[i];
while (Q--)
{
int x;
cin >> x;
if (x > p)//非法情况
cout << "Noob" << endl;
else
{
vector<int> b;
for (int i = 0; i <= n; i += x)
b.pb(i);
b.pb(n + 1);//push一个n+1,就不用最后枚举那个范围了
f[0] = 0, q[0] = 0;
hh = 0, tt = 0;
for (auto i : b)
{
while (hh <= tt && i - q[hh] > p)//由于每次移动并不一定是1,就写while而不是if
hh++;
f[i] = f[q[hh]] + a[i];
while (hh <= tt && f[q[tt]] < f[i])
tt--;
q[++tt] = i;
}
cout << f[n + 1] << endl;
}
}
}