滑动窗口(引入)![](https://i-blog.csdnimg.cn/blog_migrate/41874d85a1b6a3fea1eed3bc5432973a.png)
可以明确知道,暴力肯定会超时,现在引入单调队列来进行优化。
1.队列大小不超过k,这个由当前元素下标和队首存储下标差值计算,即 i - m + 1 > q[hh]
2.要保证队列内部元素是单调的,即 while (hh <= tt && a[i] <= a[q[tt]]) tt--; while (hh <= tt && a[i] >= a[q[tt]]) tt--; 分别表示队首到队尾递增和递减
3.将当前元素在2的条件下存入队列
4.输出满足结果,先3后4
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int, int>
#define xx first
#define yy second
#define ULL unsigned long long
const int N = 1e6 + 10;
const int M = 1e3 + 10;
const int INF = 1e18;
const int ENF = -1e18;
const int mod = 1e9 + 7;
void ClearFloat()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
int read()
{
int ret = 0, f = 1;
char ch = getchar();
while ('0' > ch || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
{
ret = ret * 10 + ch - '0';
ch = getchar();
}
return ret * f;
}
int n, k, m, t, x, a[N], w[N], v[N], f[N], q[N];
int hh = 0, tt = -1;
bool st[N];
bool cmp(int a, int b)
{
return a > b;
}
signed main()
{
ClearFloat();
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++)
{
if (hh <= tt && i - m + 1 > q[hh]) hh++;
while (hh <= tt && a[i] <= a[q[tt]]) tt--;
q[++tt] = i;
if (i >= m - 1) cout << a[q[hh]] << ' ';
}
cout << endl;
hh = 0, tt = -1;
for (int i = 0; i < n; i++)
{
if (hh <= tt && i - m + 1 > q[hh]) hh++;
while (hh <= tt && a[i] >= a[q[tt]]) tt--;
q[++tt] = i;
if (i >= m - 1) cout << a[q[hh]] << ' ';
}
}
多重背包问题 (队列优化)
多重背包的原始状态转移方程:
f(i,j)=max(f(i−1,j),f(i−1,j−v)+w,⋯,f(i−1,j−sv)+sw)
f(i,j−v)=max(f(i−1,j−v),f(i−1,j−2v)+w,⋯,f(i−1,j−(s+1)v)+(s)w)
f(i,j−2v)=max(f(i−1,j−2v),f(i−1,j−3v)+w,⋯,f(i−1,j−(s+2)v)+sw)
...
此处我们取 r = j % v
f(i,r+sv)=max(f(i−1,r+sv),f(i−1,r+(s−1)v)+w,⋯,f(i−1,r)+sw)
⋯
f(i,r+2v)=max(f(i−1,r+2v),f(i−1,r+v)+w,f(i−1,r)+2w)
f(i,r+v)=max(f(i−1,r+v),f(i−1,r)+w)
f(i,r)=f(i−1,r)
此处引用铅笔佬的解析
则可以利用滑动窗口在线性时间内求出答案
可以二维,但是内存卡的很紧
二维朴素版
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define PII pair<int, int>
#define xx first
#define yy second
#define ULL unsigned long long
const int N = 1e6 + 10;
const int M = 1e3 + 10;
const int INF = 1e18;
const int ENF = -1e18;
const int mod = 1e9 + 7;
int n, m, w[1010], v[1010], f[1010][20010], s[1010], q[20010];
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];
for(int i = 1; i <= n; i ++)
{
for(int r = 0; r < v[i]; r ++ )
{
int hh = 0, tt = -1;
for(int j = r; j <= m; j += v[i])
{
while(hh <= tt && j - q[hh] > s[i] * v[i]) hh++;
while(hh <= tt && f[i - 1][q[tt]] + (j - q[tt]) / v[i] * w[i] <= f[i - 1][j]) --tt;
q[++tt] = j;
f[i][j] = f[i - 1][q[hh]] + (j - q[hh]) / v[i] * w[i];
}
}
}
cout << f[n][m] << endl;
}
一维优化版
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define PII pair<int, int>
#define xx first
#define yy second
#define ULL unsigned long long
const int N = 20010;
const int M = 1e3 + 10;
const int INF = 1e18;
const int ENF = -1e18;
const int mod = 1e9 + 7;
void ClearFloat()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
int read()
{
int ret = 0, f = 1;
char ch = getchar();
while ('0' > ch || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
{
ret = ret * 10 + ch - '0';
ch = getchar();
}
return ret * f;
}
int n, m, t, x, v[N], w[N], s[N], f[N], g[N], q[N];
signed main()
{
ClearFloat();
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> v[i] >> w[i] >> s[i];
for (int i = 1; i <= n; ++i)
{
memcpy(g, f, sizeof g);//g存储f[i - 1][j]
for (int r = 0; r < v[i]; r++)
{
int hh = 0, tt = -1;
for (int j = r; j <= m; j += v[i])
{
while (hh <= tt && j - q[hh] > s[i] * v[i]) hh++;
while (hh <= tt && g[q[tt]] + (j - q[tt]) / v[i] * w[i] <= g[j]) --tt;//f[i][j] = max(f[i][j], f[i - 1][j - s * v[i]] + s * w)
q[++tt] = j;
f[j] = g[q[hh]] + (j - q[hh]) / v[i] * w[i];
}
}
}
cout << f[m] << endl;
}