股票交易

调了好久的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;
}
原文地址:https://www.cnblogs.com/qwq-/p/14061093.html