码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-11-02 14:01:24      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:数据   printf   line   tor   ++   n+1   fine   algorithm   code   

其实就是个大模拟。

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

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

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

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

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

不妨考虑从后往前依次插入\(H_i\),然后动态维护\(H_i\sim 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\n",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\n",resa,resb);
    }
    return 0;
}

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

标签:数据   printf   line   tor   ++   n+1   fine   algorithm   code   

原文地址:https://www.cnblogs.com/DarkValkyrie/p/11781347.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!