2017-9-19考试总结

一共考了两道题
一共水了70分(-_-||)【我还是太水了】
先说第二题,一道 区间更新,区间查询 的题目
上线段树,结果打了两百多行只有十分,别人n*n水了90分。。。
这题的难点是如何处理延迟标记
注意:在down中,左右儿子只对父亲传入的延迟标记进行更新

void down(int p) {
    if(tree[p].q==-1&&tree[p].f==0)return;
    if(tree[p].q!=-1){
        tree[p<<1].f=0;
        tree[p<<1|1].f=0; 
        tree[p<<1].q=tree[p].q;
        tree[p<<1|1].q=tree[p].q;
        if(tree[p].q==0)mem0(p<<1),mem0(p<<1|1);
        else mem1(p<<1),mem1(p<<1|1);
        tree[p].q=-1;
    }
    if(tree[p].f==1){
        change(p<<1),change(p<<1|1);
        tree[p<<1].f^=1;
        tree[p<<1|1].f^=1;      
    }
    tree[p].f=0;
}

第二题

题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。

通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。

另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过MaxP。

在第1天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?

输入 输入数据第一行包括3个整数,分别是T,MaxP,W。

接下来T行,第i行代表第i-1天的股票走势,每行4个整数,分别表示APi,BPi,ASi,BSi。

输出 输出数据为一行,包括1个数字,表示lxhgww能赚到的最多的钱数。

信息较多
但经分析可得状态转移方程(买):
dp[i][j]=max(dp[i][j],dp[ii][jj]-(j-jj)*ap[i])
//将ii天的jj张股票在第i天扩充成j张
分离参数(重点)得

dp[i][j]=dp[i-1][j]
dp[i][j]=max(dp[ii][jj]+jj*ap[i]){max(0,j-W-1)<jj<j}+j*ap[i]

由于在i j的循环中ii,jj,ap[i]都可预处理出来,
所以可以用线段树或单调队列完成查询
下面给出单调队列解法:

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DOR(i,a,b) for(int i=(a);i>=(b);i--)
#define M 2005
using namespace std;
int ap[M],bp[M],as[M],bs[M];
int dp[M][M];
int Q1[M],Q2[M];
int D[M],D1[M];
inline int max(int x,int y){if(x>y)return x;return y;}
int main(){
    int T,mx,W;
    scanf("%d%d%d",&T,&mx,&W);
    FOR(i,1,T)scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    memset(dp,-63,sizeof(dp));
    FOR(i,1,W+1)FOR(j,0,mx){
        if(j<=as[i])dp[i][j]=-j*ap[i];
        if(i>1)dp[i][j]=max(dp[i][j],dp[i-1][j]);
    }
    FOR(i,W+2,T){
        memset(Q1,0,sizeof(Q1));
        memset(Q2,0,sizeof(Q2));
        int ii=i-W-1;
        FOR(j,0,mx){
            D[j]=dp[ii][j]+j*bp[i];
            D1[j]=dp[ii][j]+j*ap[i];
        }
        FOR(j,0,mx)dp[i][j]=max(dp[i][j],dp[i-1][j]);
        int L=0,R=-1;
        DOR(j,mx,0){
            while(L<=R&&D[Q1[R]]<=D[j])R--;
            Q1[++R]=j;
            while(L<=R&&Q1[L]-j>bs[i])L++;
            dp[i][j]=max(dp[i][j],D[Q1[L]]-j*bp[i]);
        }
        L=0,R=-1;
        FOR(j,0,mx){
            while(L<=R&&D1[Q2[R]]<=D1[j])R--;
            Q2[++R]=j;
            while(L<=R&&j-Q2[L]>as[i])L++;
            dp[i][j]=max(dp[i][j],D1[Q2[L]]-j*ap[i]);
        }
    }
    int ans=0;
    FOR(i,0,mx)ans=max(ans,dp[T][i]);
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值