zoukankan      html  css  js  c++  java
  • [NOIP2012]开车旅行

    step1

    设两个数组 (A)(B)
    (A_i)(B_i) 表示在 (i) 城市时,小 (A) 和小 (B) 分别会选择去哪个点。
    考虑如何预处理这两个数组。
    观察到两个城市之间的距离就是两个城市海拔之差的绝对值,所以可以先根据每个城市的海拔进行排序。
    排完序后, (A_i)(B_i) 其实就是从以 (i-1)(i+1)(i-2)(i+2) 这四个数为下标的海拔中找出离当前点第二近的和最近的点。
    但是,由于编号较小的城市在编号较大的城市的西边,所以为了让车不往回开还需要把已经处理好的点从数列中删除。
    故可以用双向链表实现。
    这块的复杂度为 (O(n log n))

    step2

    设数组 (f)(f_{i,j}) 表示两人从 (i) 城市出发轮流开 (2^j) 天会到哪个点。
    设数组 (FA)(FB) ,分别表示小 (A) 和小 (B)(i) 城市出发轮流开 (2^j) 天各会走多少路程。
    先预处理 (f)
    初值
    (f_{i,0}) 就是从 (i) 城市出发,两人各走一步所到的城市。
    (f_{i,0}=B_{A_i})
    转移
    因为两个人在每个点所会去的城市都是固定的,所以可以直接转移。
    (f_{i,j}=f_{f_{i,j-1} ,j-1})
    接下来,预处理 (FA)(FB)
    为了方便,用 (dis(i,j)) 表示 (i) 城市到 (j) 城市的距离。
    初值
    比较显然。
    (FA_{i,0}=dis(i,A_i))
    (FB_{i,0}=dis(A_i,B_{A_i}))
    转移
    (f) 类似,也可以直接转移。
    (FA_{i,j}=FA_{i,j-1}+FA_{f_{i,j-1} ,j-1})
    (FB_{i,j}=FB_{i,j-1}+FB_{f_{i,j-1} ,j-1})
    这块的复杂度也是 (O(n log n))

    step3

    处理询问。
    第一问其实是和第二问类似的,只要枚举出发点即可。故下面只考虑第二问。
    可以把小 (A) 和小 (B) 并在一起处理,和普通的倍增处理类似。
    但是,由于小 (A) 是先走的,所以最后还要判断一下小 (A) 能不能再走一步。
    第一问的复杂度为 (O(n log n)) ,第二问的复杂度为 (O(m log n))
    总复杂度为 (O(n log n+m log n)) ,可以通过此题。

    code

    我的代码写的有亿点丑陋,但还是放一下吧。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    const int N=1e5+10;
    const double inf=1e18;
    int n,a[N];
    int A[N],B[N];
    int f[N][20]; 
    int FA[N][20],FB[N][20];
    int X,Y;
    struct node
    {
    	int id,num;
    	int pre,nxt;
    }b[N];
    bool cmp(node x,node y)
    {
    	return x.num<y.num;
    }
    bool CMP(node x,node y)
    {
    	return x.id<y.id;
    }
    int ABS(int x)
    {
    	return x>0?x:-x;
    }
    int get(int x,int y)
    {
    	return ABS(b[x].num-b[y].num);
    }
    void GET(int x,int y)
    {
    	X=0,Y=0;
    	for(int i=19;i>=0;i--)
    		if(f[x][i]&&X+Y+FA[x][i]+FB[x][i]<=y)
    			X+=FA[x][i],Y+=FB[x][i],x=f[x][i];
    	if(A[x]&&X+Y+FA[x][0]<=y) X+=FA[x][0];
    } 
    signed main()
    {
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	b[0].num=inf;
    	for(int i=1;i<=n;i++)
    		b[i].id=i,b[i].num=a[i];
    	sort(b+1,b+n+1,cmp);
    	for(int i=1;i<=n;i++)
    		b[i].pre=b[i-1].id,b[i].nxt=b[i+1].id;
    	b[1].pre=0,b[n].nxt=0;
    	sort(b+1,b+n+1,CMP);
    	for(int i=1;i<=n;i++)
    	{
    		if(!b[i].pre)
    		{
    			B[i]=b[i].nxt;
    			A[i]=b[b[i].nxt].nxt;
    			b[b[i].nxt].pre=b[i].pre;
    			continue;
    		}
    		if(!b[i].nxt)
    		{
    			B[i]=b[i].pre;
    			A[i]=b[b[i].pre].pre;
    			b[b[i].pre].nxt=b[i].nxt;
    			continue;
    		}
    		if(get(i,b[i].pre)<=get(i,b[i].nxt))
    		{
    			B[i]=b[i].pre;
    			if(get(i,b[b[i].pre].pre)<=get(i,b[i].nxt)) A[i]=b[b[i].pre].pre;
    			else A[i]=b[i].nxt;
    		}
    		else
    		{
    			B[i]=b[i].nxt;
    			if(get(i,b[i].pre)<=get(i,b[b[i].nxt].nxt)) A[i]=b[i].pre;
    			else A[i]=b[b[i].nxt].nxt;
    		}
    		b[b[i].nxt].pre=b[i].pre;
    		b[b[i].pre].nxt=b[i].nxt;
    	}
    	for(int i=1;i<=n;i++) f[i][0]=B[A[i]];
    	for(int j=1;j<20;j++)
    		for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
    	for(int i=1;i<=n;i++)
    	{
    		FA[i][0]=get(i,A[i]);
    		FB[i][0]=get(A[i],B[A[i]]);
    	}
    	for(int j=1;j<20;j++)
    		for(int i=1;i<=n;i++)
    		{
    			FA[i][j]=FA[i][j-1]+FA[f[i][j-1]][j-1];
    			FB[i][j]=FB[i][j-1]+FB[f[i][j-1]][j-1];
    		}
    	int x,s=0;
    	double ans=inf;
    	scanf("%lld",&x);
    	for(int i=1;i<=n;i++)
    	{
    		GET(i,x);
    		if(Y==0)
    		{
    			if(ans==inf&&a[i]>a[s]) s=i;
    		}
    		else
    		{
    			if(ans>(double)(X)/(double)(Y)) ans=(double)(X)/(double)(Y),s=i;
    			else if(ans==(double)(X)/(double)(Y)&&a[i]>a[s]) s=i;
    		}
    	}
    	printf("%lld
    ",s);
    	int m;
    	scanf("%lld",&m);
    	while(m--)
    	{
    		scanf("%lld%lld",&s,&x);
    		GET(s,x);
    		printf("%lld %lld
    ",X,Y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    新一代MQ apache pulsar的架构与核心概念
    Flutter使用fluwx实现微信分享
    BZOJ3622 已经没有什么好害怕的了 动态规划 容斥原理 组合数学
    NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分
    Codeforces 555C Case of Chocolate 其他
    NOIP2017提高组Day2T3 列队 洛谷P3960 线段树
    NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
    NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序
    Codeforces 873F Forbidden Indices 字符串 SAM/(SA+单调栈)
    Codeforces 873E Awards For Contestants ST表
  • 原文地址:https://www.cnblogs.com/zhs1/p/14009095.html
Copyright © 2011-2022 走看看