• P1081 开车旅行[倍增](毒瘤题)


    其实就是个大模拟。

    首先,根据题意,小A和小B从任意一个城市开始走,无论(X)如何,其路径是一定唯一的。

    显然对于两问都可以想出一个(O(n^2))的暴力,即直接一步一步地向右走。

    首先,我们当然需要知道A,B在每个城市的下一步如何走,记(nexta(i),nextb(i))为A,B在(i)处时,下一步走到的城市编号。

    考虑如何高效(复杂度小于等于(O(nlogn)))维护两个(next)

    显然不能直接维护每个城市与其后面的城市的差值,再好的数据结构也会到(O(n^2))

    不妨考虑从后往前依次插入(H_i),然后动态维护(H_isim H_n)的有序集合。这样的话,在有序集合中,最小的差值一定要么是(H_i)与其前驱,要么就是与其后继的差值。次小的差值,就是(H_i)前驱、前驱的前驱、后继、后继的后继与(H_i)的差值的次小值。这个问题,平衡树解决之,预处理(O(nlogn))

    下面考虑走(k)步的情况,当前步是A走还是B走与步数的奇偶性有关,因此我们还要分开讨论。

    那么,我们不妨考虑以此为基础进行优化,比如优化到(O(nlogn))。显然地,对于这样的问题,我们可以倍增预处理,(O(logn))询问。

    接下来考察我们需要什么信息,分别是(i)向后走(k)步的城市,A和B从(i)向后走(k)步的路程。

    (f[0/1][i][j])为从(i)位置,0A,1B向后走(2^j)步的城市。

    显然

    [f[0][i][0]=nexta(i)\f[1][i][0]=nextb(i) ]

    由于,走(2^0)步是走奇数步,有转移

    [f[0][i][1]=f[1][f[0][i][0]][0]\f[1][i][1]=f[0][f[1][i][0]][0] ]

    对于走(2^j)步,有

    [f[0][i][j]=f[0][f[0][i][j-1]][j-1]\f[1][i][j]=f[1][f[1][i][j-1]][j-1] ]

    (da[0/1][i][j])表示从(i)位置,A向后走(2^j)步的路程,且现在(当前步)是0A,1B在开车,还没走时的A开的距离

    显然

    [da[0][i][0]=dist(i,nexta(i))\da[1][i][0]=0 ]

    有转移

    [da[0][i][1]=da[0][i][0]+da[1][f[0][i][0]][0]\da[1][i][1]=da[1][i][0]+da[0][f[1][i][0]][0]\da[0][i][j]=da[0][i][j-1]+da[0][f[0][i][j-1]][j-1]\da[1][i][j]=da[1][i][j-1]+da[1][f[1][i][j-1]][j-1] ]

    (db[0/1][i][j])表示从(i)位置,B向后走(2^j)步的路程,且现在是0A,1B在开车。

    (da)差别不大,不再赘述。


    预处理完成之后,我们开始考虑题述问题。

    对于第一问,对给出的(X_0),我们枚举城市(S_i),倍增统计走(X_0)步的答案(当然超出(N)要特判),(O(nlogn))解决之。

    对于第二问,同样的,对于每一组(S_i,X_i),直接倍增统计即可,复杂度(O(mlogn))

    总复杂度在(O((n+m)logn))左右,完全可以通过本题。

    注意,这道题的细节之数量足以让人去世。

    代码未经重构,很丑。

    参考代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<cstdlib>
    #include<queue>
    #include<set>
    #include<map>
    #include<vector>
    #define INF 0x7fffffff
    #define PI acos(-1.0)
    #define N 100010
    #define MOD 2520
    #define E 1e-12
    #define ll long long
    using namespace std;
    inline ll read()
    {
    	ll f=1,x=0;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    set<int> h;
    map<int,int> mp;
    int t;
    ll n,a[N],na[N],nb[N],f[2][N][21],da[2][N][21],db[2][N][21];
    int main()
    {
    	n=read();t=log2(n);
    	for(int i=1;i<=n;++i) a[i]=read();
    	a[0]=INF,a[n+1]=-INF;
    	h.insert(INF);
    	h.insert(-INF);
    	mp[-INF]=0,mp[INF]=n+1;
    	for(int i=n;i>=1;--i){
    		h.insert(a[i]);mp[a[i]]=i;
    		ll n1=((++h.find(a[i])!=h.end())?(*++h.find(a[i])):INF),n2=(((++(++h.find(a[i])))!=h.end())?(*++(++h.find(a[i]))):INF);
    		ll p1=((h.find(a[i])!=h.begin())?(*--h.find(a[i])):-INF),p2=((--h.find(a[i])!=h.end())?(*--(--h.find(a[i]))):-INF);
    		if(n1-a[i]>=a[i]-p1){
    			nb[i]=mp[p1];
    			na[i]=(n1-a[i]>=a[i]-p2)?mp[p2]:mp[n1];
    		}
    		else{
    			nb[i]=mp[n1];
    			na[i]=(n2-a[i]>=a[i]-p1)?mp[p1]:mp[n2];
    		}
    		f[0][i][0]=na[i];f[1][i][0]=nb[i];
    		da[0][i][0]=abs(a[i]-a[na[i]]);
    		db[1][i][0]=abs(a[i]-a[nb[i]]);
    	}
    	for(int j=1;j<=t;++j){
    		for(int i=1;i<=n;++i){
    			if(j==1){
    				f[0][i][1]=f[1][f[0][i][0]][0];
    				f[1][i][1]=f[0][f[1][i][0]][0];
    				da[0][i][1]=da[0][i][0]+da[1][f[0][i][0]][0];
    				da[1][i][1]=da[1][i][0]+da[0][f[1][i][0]][0];
    				db[0][i][1]=db[0][i][0]+db[1][f[0][i][0]][0];
    				db[1][i][1]=db[1][i][0]+db[0][f[1][i][0]][0];
    			}else{
    				f[0][i][j]=f[0][f[0][i][j-1]][j-1];
    				f[1][i][j]=f[1][f[1][i][j-1]][j-1];
    				da[0][i][j]=da[0][i][j-1]+da[0][f[0][i][j-1]][j-1];
    				da[1][i][j]=da[1][i][j-1]+da[1][f[1][i][j-1]][j-1];
    				db[0][i][j]=db[0][i][j-1]+db[0][f[0][i][j-1]][j-1];
    				db[1][i][j]=db[1][i][j-1]+db[1][f[1][i][j-1]][j-1];
    			}
    		}
    	}/
    	int x0=read(),s0=0;
    	double ans=1e14,nans=1e14;//task 1
    	for(int i=1;i<=n;++i){
    		int now=i;
    		ll resa=0,resb=0;
    		for(int j=t;j>=0;--j){
    			if(f[0][now][j]){
    				if(resa+resb+da[0][now][j]+db[0][now][j]>x0)
    					continue;
    				resa+=da[0][now][j];resb+=db[0][now][j];
    				now=f[0][now][j];
    			}
    		}
    		nans=(double)resa/(double)resb;
    		if(nans<ans){
    			ans=nans,s0=i;
    		}
    		else{
    			if(nans==ans&&a[s0]<a[i]) s0=i;
    		}
    	}
    	printf("%d
    ",s0);
    	int m=read();//task 2
    	while(m--){
    		ll si=read(),xi=read();
    		ll resa=0,resb=0,now=si;
    		for(int j=t;j>=0;--j){
    			if(f[0][now][j]){
    				if(resa+resb+da[0][now][j]+db[0][now][j]>xi)
    					continue;
    				resa+=da[0][now][j];resb+=db[0][now][j];
    				now=f[0][now][j];
    			}
    		}
    		printf("%lld %lld
    ",resa,resb);
    	}
    	return 0;
    }
    
  • 相关阅读:
    gcc5.2版本安装详解
    Java的各种加密算法
    Response.ContentType 详细列表
    使用C#选择文件夹、打开文件夹、选择文件
    C#从SQL server数据库中读取l图片和存入图片
    GridView导出成Excel字符"0"丢失/数字丢失的处理方式 收藏
    只能在执行Render() 的过程中调用 RegisterForEventValidation;
    维护删除订单后,清空安装和售后信息;条码打印软件补充打印问题
    Bind("入库日期", "{0:yyyy-MM-dd}") 关于asp.net格式化数据库日期字符串
    特别注意: range.Text.ToString(); 和 range.Value2.ToString(); 的区别
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11781347.html
Copyright © 2020-2023  润新知