題面描述
思路
這道題DP的很明顯啊(可惜我就是不會寫啊)
提前聲明:
這裏的爲,爲,爲,爲,爲,b爲,爲
首先根據題意,因爲天買了股票,天也不能買股票,乾脆,
狀態轉移方程:
第一條方程就是這天啥都不幹(真是個有趣的傢伙)。
第二條方程就是在前天買進張股票。
第三條方程就是在前天已經買了k張股票,在天再買張股票。
第三條方程就是在前天買了k張股票,在天賣剩張股票。
這種已經可以拿下分了,
然後呢?(就T的沒邊了)
觀察許久,我發現貌似第、個方程可以單調隊列優化。
(因爲它們具有單調性)
踢隊頭很好寫,踢隊尾可以觀察發現有共性:
因此我們就可以以這個爲標準,踢掉不優的隊尾。
while(l<=r&&f[i-t][j]+a*j>=f[i-t][q[r]]+a*q[r])--r;
while(l<=r&&f[i-t][j]+c*j>=f[i-t][q[r]]+c*q[r])--r;
貌似這道題就結束了?
AC code
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define gc getchar()
using namespace std;
const int N=2010;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int f[N][N];
int q[N];
int main()
{
int n,m,t;qr(n),qr(m),qr(t);t++;
f[0][0]=-N*N;for(int j=1;j<=m+1;j++)f[0][j]=f[0][j-1];
for(int i=1;i<=n;i++)
{
int a,b,c,d,l,r;
qr(a),qr(c),qr(b),qr(d);
for(int j=0;j<=m+1;j++)f[i][j]=f[i-1][j];
for(int j=0;j<=b;j++)f[i][j]=max(f[i][j],-a*j);
if(i>t)
{
l=1;r=0;q[1]=0;
for(int j=0;j<=m;j++)
{
while(l<=r&&q[l]<j-b)++l;
f[i][j]=max(f[i][j],f[i-t][q[l]]-a*j+a*q[l]);
while(l<=r&&f[i-t][j]+a*j>=f[i-t][q[r]]+a*q[r])--r;
q[++r]=j;
}
l=1;r=0;q[1]=m+1;
for(int j=m;j>=0;j--)
{
while(l<=r&&q[l]-j>d)++l;
f[i][j]=max(f[i][j],f[i-t][q[l]]+c*q[l]-c*j);
while(l<=r&&f[i-t][j]+c*j>=f[i-t][q[r]]+c*q[r])--r;
q[++r]=j;
}
}
}
qw(f[n][0]);puts("");
return 0;
}