首页 > 其他分享 >P1081 [NOIP2012 提高组] 开车旅行

P1081 [NOIP2012 提高组] 开车旅行

时间:2024-07-30 09:29:50浏览次数:15  
标签:旅行 dp2 dp1 -- NOIP2012 read P1081 ll define

思路:

首先令 \(nxt1_i\) 表示右侧最近的城市距离(\(id1_i\) 为编号),令 \(nxt2_i\) 表示右侧第二近的城市编号(\(id2_i\) 为编号);可以使用 set 找出离这个城市最近的 \(4\) 个城市(前面两个,后面两个)。

定义:

  • \(f_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮最后到达的位置。

  • \(dp1_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮最后 A 走过的距离。

  • \(dp2_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮最后 B 走过的距离。

初始化:

\[f_{i,0} = id1_{id2_i} \]

\[dp1_{i,0} = nxt2_{i} \]

\[dp2_{i,0} = nxt1_{id2_i} \]

状态转移方程为:

\[f_{i,j} = f_{f_{i,j-1},j-1} \]

\[dp1_{i,j} = dp1_{i,j-1} + dp1_{f_{i,j-1},j-1} \]

\[dp2_{i,j} = dp2_{i,j-1} + dp2_{f_{i,j-1},j-1} \]

此时对于询问 \(1\) 和询问 \(2\):

  • 本质上是求出从每个城市出发后 \(A\) 走的距离与 \(B\) 走的距离。

  • 那么考虑从高位到低位贪心,即设当前跳到了 \(s\) 点,若 \(dp1_{s,i} + dp2_{s,i} \le x\),可以从 \(s\) 跳到 \(f_{s,i}\),需要令 \(x \gets x - (dp1_{s,i} + dp2_{s,i})\),然后继续遍历 \(i-1\) 位。

  • 因为是 A 先开车,所以 A 可能会在最后一轮结束后还能再开上一次,需要特判。

时间复杂度为 \(O((N+Q) \log N)\)。

完整代码:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=1e5+10,M=18,INF=1e18;
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
struct Node{
	ll a,b;
	ll id;
	bool operator<(const Node&rhs)const{
		if(a!=rhs.a)
		  return a<rhs.a;
		return b<rhs.b;
	}
};
ll n,m,s,x,x0,s0,cnt,dis1,dis2,disa,disb;
ll a[N],nxt1[N],nxt2[N],id1[N],id2[N];
ll f[N][M],dp1[N][M],dp2[N][M];
Node h[N];
vector<Node> V;
multiset<Node> S;
void solve(ll s,ll x){
	dis1=dis2=0;
	for(int i=M-1;i>=0;i--){
		if(dp1[s][i]+dp2[s][i]<=x&&f[s][i]){
			dis1+=dp1[s][i],dis2+=dp2[s][i];
			x-=dp1[s][i]+dp2[s][i];
			s=f[s][i];
		}
	}
	if(nxt2[s]<=x)
	  dis1+=nxt2[s];
}
bool End;
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		h[i]={a[i],a[i],i};
	}
	S.insert({INF,INF,0});
	S.insert({INF-1,INF-1,0});
	S.insert({-INF,-INF,0});
	S.insert({-INF+1,-INF+1,0});
	for(int i=n;i>=1;i--){
		V.clear();
		V.push_back(*--S.lower_bound(h[i]));
		V.push_back(*--S.lower_bound(V[0]));
		V.push_back(*S.upper_bound(h[i]));
		V.push_back(*S.upper_bound(V[2]));
		for(auto &v:V)
		  v.a=abs(h[i].a-v.a);
		sort(V.begin(),V.end());
		nxt1[i]=V[0].a,nxt2[i]=V[1].a;
		id1[i]=V[0].id,id2[i]=V[1].id;
		cerr<<id1[i]<<' '<<id2[i]<<'\n';
		S.insert(h[i]);
	}
	for(int i=1;i<=n;i++){
		f[i][0]=id1[id2[i]];
		dp1[i][0]=nxt2[i];
		dp2[i][0]=nxt1[id2[i]];
	}
	for(int j=1;j<M;j++){
		for(int i=n;i>=1;i--){
			f[i][j]=f[f[i][j-1]][j-1];
			dp1[i][j]=dp1[i][j-1]+dp1[f[i][j-1]][j-1];
			dp2[i][j]=dp2[i][j-1]+dp2[f[i][j-1]][j-1];
		}
	}
	x0=read();
	for(int i=1;i<=n;i++){
		solve(i,x0);
		if(dis2&&(!s0||disa*dis2>disb*dis1)){
			s0=i;
			disa=dis1,disb=dis2;
		}
	}
	write(s0);
	putchar('\n');
	m=read();
	while(m--){
		s=read(),x=read();
		solve(s,x);
		write(dis1);
		putchar(' ');
		write(dis2);
		putchar('\n');
	}
	cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
	return 0;
}

标签:旅行,dp2,dp1,--,NOIP2012,read,P1081,ll,define
From: https://www.cnblogs.com/rgw2010/p/18331306

相关文章

  • 牛的旅行
    //牛的旅行.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。//#include<iostream>#include<cmath>#include<algorithm>#include<cstring>usingnamespacestd;/*https://www.acwing.com/problem/content/1127/农民John的农场里有很多牧区,有的路径......
  • 题解:P10815 【模板】快速读入
    闲着没事儿水篇tj题目大意题目大意极其粗暴,记得\(10^8\times10^8=10^{16}>2^{31}-1\)会爆int,开longlong就好。于是这个题就变成了一个读入输出优化模板题。这不又回去了。另外,输入输出常数优化也很常用,抢最优解和骗分时都可以用上。1cin/cout版本操作ios::......
  • 数学建模--旅行商
     目录数学模型解决方法应用场景结论旅行商问题的最新启发式算法有哪些?如何评估不同旅行商问题求解方法的效率和准确性?旅行商问题在实际应用中的最新进展是什么?针对大规模旅行商问题,目前存在哪些高效的近似算法?旅行商问题的数学模型在其他领域(如生物信息学、材料科学......
  • P10812 【MX-S2-T3】跳 题解
    题目分析考虑DP。显然当没有\(i\)连向\(i+1\)的边时,整个图是一个DAG,可以直接DP。所以我们DP要解决的唯一问题,就是考虑上\(i\)到\(i+1\)的边。考虑从\(n\)走到\(1\)的过程。当我们从\(i\)向前跳到\(j\)后,此时我们要么向前跳,要么往回走。又因为不能经过重复......
  • 旅行
    怎么感觉杭电OJ有好几台不同的评测机,而且评测机之间不但速度不同,而且对代码长度的统计都不同?理论上答案是可以超过int存储范围的,反正没有这种数据,我不管了点击查看代码#include<bits/stdc++.h>usingnamespacestd;vector<int>a[200005];intc[200005],w[200005];intf......
  • P1082 [NOIP2012 提高组] 同余方程
    [NOIP2012提高组]同余方程解法在这个问题中,我们想要找到......
  • 【Python datetime模块精讲】:时间旅行者的日志,精准操控日期与时间
    当然,让我们深入探讨Python的datetime模块,详细解释其功能和用法。Pythondatetime模块:时间旅行者的日志在编程中,日期和时间的处理是一个常见但复杂的问题。幸运的是,Python的datetime模块为我们提供了一套全面的解决方案。这个模块不仅包括日期和时间的基本表示,还提供......
  • Java计算机毕业设计旅行分享平台(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在数字化时代,旅游行业正经历着前所未有的变革。随着人们生活水平的提高和休闲方式的多样化,旅行已成为现代人追求生活品质、拓宽视野的重要方式之一。......
  • [NOIP2012 普及组] 摆花(含代码)
    [NOIP2012普及组]摆花题目描述小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共mmm盆。通过调查顾客的喜好,小明列出了顾客最喜欢的......
  • 计算机课设——安卓旅行日志
    计算机课设——安卓旅行日志私信获取完整代码本项目用到很多第三方开源库,特此感谢这些大大开源的库,同时也感谢csdn许多博客的启发。......