zoukankan      html  css  js  c++  java
  • 股票交易

    调了好久的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;
    }
    
  • 相关阅读:
    TWebBrowser 与 MSHTML(3): window 对象的属性、方法、事件纵览
    使 SaveDialog 对话框的文件名选择变灰 回复 "delphan" 的问题
    [最新通知]今日17:0019:00将不能访问博客园
    编辑器改进(三)
    博客园.Text技术支持移至PSP技术支持中心
    [公告]关于投稿到Dearbook的“读书笔记”专栏
    [致歉]博客园服务器停运时间超出计划时间
    [博客园公告]给发表评论增加了验证码功能
    CS Beta 1发布了
    [通知]11月6日(星期六)可能不能访问博客园
  • 原文地址:https://www.cnblogs.com/qwq-/p/14061093.html
Copyright © 2011-2022 走看看