zoukankan      html  css  js  c++  java
  • [IOI2009]salesman

    CI.[IOI2009]salesman

    思想非常simple:因为一次从上游往下游的转移,可以被表示成

    \(f_i+(pos_i-pos_j)\times U\rightarrow f_j\ |\ pos_i<pos_j\land tim_i<tim_j\)

    拆开括号,即可得到两半互不相关的部分。然后直接使用线段树/树状数组进行转移即可。

    从下游往上游的转移也可以类似地处理。

    现在考虑\(tim\)中可能有相等的情形,并不能确定访问顺序。这个再使用一遍辅助DP过一遍就行了。有一个结论是当\(tim\)相等时,一次转移中一定不会走回头路——回头路的部分完全可以在上次转移和下次转移处就处理掉了。然后就直接DP过就行了。

    3min就能想出的idea,我整整调了3d。主要因为一开始套了两重离散化,后来发现数据范围开的下便删去了离散化;一开始写的是线段树,后来发现线段树debug起来很麻烦,便换成了BIT;一开始也没有想到没有回头路的情形,辅助DP时写的极其憋屈(后来证明就是这个憋屈的DP中有一处\(U\)\(D\)写反了);同时中文题面翻译还翻译错了,这个“距离”是到上游的距离而非到下游的距离。于是种种因素叠加在一起,debug得精神崩溃。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int inf=0xc0c0c0c0;
    const int N=1001000;
    int n,U,D,S,tim[N],pos[N],bon[N],m=500100,ord[N],f[N],g[N],upper[N],lower[N];//upper:the maximal when go against the wave; lower:vice versa
    void modify(int P,int val){
    	for(int x=P;x;x-=x&-x)upper[x]=max(upper[x],val-P*U);
    	for(int x=P;x<=m;x+=x&-x)lower[x]=max(lower[x],val+P*D);
    }
    int queryupper(int P){
    	int ret=inf;
    	for(int x=P;x<=m;x+=x&-x)ret=max(ret,upper[x]+P*U);
    	return ret;
    }
    int querylower(int P){
    	int ret=inf;
    	for(int x=P;x;x-=x&-x)ret=max(ret,lower[x]-P*D);
    	return ret;
    }
    #define I ord[i]
    #define J ord[j]
    #define K ord[k]
    int main(){
    	scanf("%d%d%d%d",&n,&U,&D,&S),memset(upper,0xc0,sizeof(upper)),memset(lower,0xc0,sizeof(lower));
    	for(int i=1;i<=n;i++)scanf("%d%d%d",&tim[i],&pos[i],&bon[i]),ord[i]=i;
    	sort(ord+1,ord+n+1,[](int x,int y){return tim[x]==tim[y]?pos[x]<pos[y]:tim[x]<tim[y];});
    	modify(S,0);
    	for(int i=1,j=1;j<=n;){
    		while(tim[I]==tim[J])f[J]=g[J]=max(queryupper(pos[J]),querylower(pos[J]))+bon[J],j++;
    		for(int k=i+1;k<j;k++)f[K]=max(f[K],f[ord[k-1]]-(pos[K]-pos[ord[k-1]])*D+bon[K]);
    		for(int k=j-2;k>=i;k--)g[K]=max(g[K],g[ord[k+1]]-(pos[ord[k+1]]-pos[K])*U+bon[K]);
    		while(i<j)modify(pos[I],max(f[I],g[I])),i++;
    	}
    	printf("%d\n",max(queryupper(S),querylower(S)));
    	return 0;
    }
    

  • 相关阅读:
    注册表修改大全(浏览文章时可以使用CTRL+F查找)
    怎样彻底删除系统服务项
    Linux查看文件编码格式及文件编码转换
    使用回收站主键名、索引名问题
    Aix5.3安装Bash Shell环境
    让AIX下的sqlplus也支持回显功能
    Oracle查看表空间使用率SQL脚本
    笔记本电脑内网、外网一起使用
    Oracle数据库为何出现乱码
    Oracle中varchar2(20)和varchar2(20 byte)区别
  • 原文地址:https://www.cnblogs.com/Troverld/p/14601203.html
Copyright © 2011-2022 走看看