调了好久的dp
由题解得,设dp[i][j]表示第i天拥有j张股票时最多有多少钱
大dp
#include <bits/stdc++.h>
using namespace std;
int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9')
ch = getchar();
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x;
}
int pin[5000], pout[5000], limin[5000], dp[3000][3000], limout[5000];
int main() {
int t = read(), maxp = read(), w = read();
for (int i = 1; i <= t; i++)
pin[i] = read(), pout[i] = read(), limin[i] = read(), limout[i] = read();
memset(dp, -0x3f, sizeof(dp));
dp[0][0] = 0;//注意初始化
for (int i = 1; i <= t; i++)
for (int j = 0; j <= maxp; j++) {
dp[i][j] = dp[i - 1][j];
for (int k = 0; k <= max(0, i - w - 1); k++) {//注意循环终止条件,最初的几天可以交易
for (int kk = max(j - limin[i], 0); kk < j; kk++)
dp[i][j] = max(dp[i][j], dp[k][kk] - pin[i] * (j - kk));
for (int kk = j + 1; kk <= min(j + limout[i], maxp); kk++)
dp[i][j] = max(dp[i][j], dp[k][kk] + pout[i] * (kk - j));
}
}
cout << dp[t][0];
return 0;
}
这样就有50分啦
然后显然枚举0~i-w-1天的那一层可以优化掉
#include <bits/stdc++.h>
using namespace std;
int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9')
ch = getchar();
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x;
}
int pin[5000], maxn[5000], pout[5000], limin[5000], dp[3000][3000], limout[5000];
int main() {
int t = read(), maxp = read(), w = read();
for (int i = 1; i <= t; i++)
pin[i] = read(), pout[i] = read(), limin[i] = read(), limout[i] = read();
memset(dp, -0x3f, sizeof(dp));
memset(maxn, -0x3f, sizeof(maxn));
dp[0][0] = 0;
maxn[0] = 0;//注意初始化呀
for (int i = 1; i <= t; i++) {
if (i - w - 1 >= 0)
for (int j = 0; j <= maxp; j++)
maxn[j] = max(maxn[j], dp[i - w - 1][j]);//改成这样
for (int j = maxp; j >= 0; j--) {
dp[i][j] = dp[i - 1][j];
for (int kk = max(j - limin[i], 0); kk < j; kk++)
dp[i][j] = max(dp[i][j], maxn[kk] - pin[i] * (j - kk));
for (int kk = j + 1; kk <= min(j + limout[i], maxp); kk++)
dp[i][j] = max(dp[i][j], maxn[kk] + pout[i] * (kk - j));
}
}
cout << dp[t][0];
return 0;
}
这样就有60分啦
再筛一遍股票少钱还少的屑状态就有70啦
#include <bits/stdc++.h>
using namespace std;
int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9')
ch = getchar();
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x;
}
int pin[2001], money[2001], piao[2001], maxn[2001], pout[2001], limin[2001], dp[2001][2001], limout[2001];
int main() {
int t = read(), maxp = read(), w = read();
for (int i = 1; i <= t; i++)
pin[i] = read(), pout[i] = read(), limin[i] = read(), limout[i] = read();
memset(dp, -0x3f, sizeof(dp));
memset(maxn, -0x3f, sizeof(maxn));
memset(money, -0x3f, sizeof(money));
dp[0][0] = 0, //注意初始化呀
maxn[0] = 0;
int lim;
for (register int i = 1; i <= t; i++) {
if (i - w - 1 >= 0)
for (register int j = 0; j <= maxp; j++)
maxn[j] = max(maxn[j], dp[i - w - 1][j]);
int linc = 0;
for (register int j = maxp; j >= 0; j--)
if (maxn[j] > money[linc])
money[++linc] = maxn[j], piao[linc] = j;
for (register int j = 1; j <= linc; j++) {
lim = min(piao[j] + limin[i], maxp);
for (int kk = piao[j]; kk <= lim; kk++)
dp[i][kk] = max(dp[i][kk], money[j] - pin[i] * (kk - piao[j]));
for (register int kk = max(piao[j] - limout[i], 0); kk <= piao[j]; kk++)
dp[i][kk] = max(dp[i][kk], money[j] + pout[i] * (piao[j] - kk));
}
}
int maxn = -0x3f3f3f3f;
for (register int i = 1; i <= t; i++)
maxn = max(maxn, dp[i][0]);
cout << maxn;
return 0;
}
然而还是tle
太久不写单调队列手生了QAQ
其实最开始应该把状态转移方程拆开
dp[i][j]=max(dp[k][kk] - pin[i] * (j - kk))
也就是dp[i][j]=max(dp[k][kk] - pin[i] * j + kk * pin[i]))
发现决策实质是找一个dp[k][kk] + kk * pin[i]最大
像上面一样把k那一位优化掉
pin[i]是个定值
然后这个东西只和kk有关所以可以用单调队列
#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int pin[5000],pout[5000],maxn[5000],line[5000],time_[5000],dp[3001][3001],limin[5000],limout[5000];
int main()
{
int t=read(),maxp=read(),w=read();
for(int i=1;i<=t;i++) pin[i]=read(),pout[i]=read(),limin[i]=read(),limout[i]=read();
memset(maxn,-0x3f,sizeof(maxn));
memset(dp,-0x3f,sizeof(dp));
maxn[0]=0;
dp[0][0]=0;
for(int i=1;i<=t;i++)
{
if(i-w-1>0) for(int j=0;j<=maxp;j++) maxn[j]=max(maxn[j],dp[i-w-1][j]);
int head=1,linc=0;
for(int j=0;j<=maxp;j++)
{
dp[i][j]=dp[i-1][j];
int qwq=maxn[j]+pin[i]*j;
while(head<=linc&&time_[head]<j-limin[i]) head++;
while(linc>=head&&line[linc]<qwq) linc--;
line[++linc]=qwq;
time_[linc]=j;
dp[i][j]=max(dp[i][j],line[head]-j*pin[i]);
}
head=1,linc=0;
for(int j=maxp;j>=0;j--)
{
int qwq=maxn[j]+pout[i]*j;
while(head<=linc&&time_[head]>j+limout[i]) head++;
while(linc>=head&&line[linc]<qwq) linc--;
line[++linc]=qwq;
time_[linc]=j;
dp[i][j]=max(dp[i][j],line[head]-j*pout[i]);
}
}
cout<<dp[t][0];
return 0;
}