NOIP2012 开车旅行 倍增与模拟结合后的调试神题

来源:互联网 发布:javascript知识点总结 编辑:程序博客网 时间:2024/05/06 06:58

Problem

偷个懒一定不会被发现的

题外话

话说上午才考完令人发指的[真·NOIp膜你赛],然后整个人都不好了,而且这道题目还是从昨天晚上调一直调到今天下午才A的,然而dalao们都是1A。尤其是中间在调试的时候,内心已经爆炸了。

NOIpNOIplus/NOIprofessional

Solution

其实我觉得当年NOIP出这道题还是比较良心的,暴力分有70分,也就是说单纯去模拟就有70分诶,所以打暴力的性价比是很高的!尤其在考试的时候,我肯定不会优先打这道题的正解,除非你有像 @kb 一样深厚的功力。

很明显,如果打单纯的模拟是拿不了满分的,但是看看数据范围,我们会发现只需要一个log级别的优化就可以A了,那么很容易想到用倍增进行优化,令两天为一轮,那么按照轮次来进行倍增,于是就可以预处理出走2i轮之后走到的节点以及小A走的公里数,小B走的公里数。然后按照题意分别枚举即可。但是这道题目还有一个坑点,就是枚举完轮数之后,小A有可能还是可以走,那么在最后的时候还要特判一下。

Code

#include <algorithm>#include <iostream>#include <cstdio>using namespace std;typedef long long ll;const int maxn=100010;struct data{    int l,r,h,id;    bool operator < (const data &x)const {return h<x.h;}}c[maxn];ll x;int n,m,da,db,l,r,t,ans;double minx=0x3f3f3f3f;int p[maxn],na[maxn],nb[maxn],a[maxn],b[maxn],f[maxn][21],disa[maxn][21],disb[maxn][21];int abs(int x){return x<0?-x:x;}void init(int now){    int l=c[p[now]].l,r=c[p[now]].r;    if(!r||(l&&c[p[now]].h-c[l].h<=c[r].h-c[p[now]].h))//the left point is near    {        nb[now]=c[l].id;        int ll=c[l].l;        if(!r||(ll&&c[p[now]].h-c[ll].h<=c[r].h-c[p[now]].h))          na[now]=c[ll].id;        else          na[now]=c[r].id;    }    else    {        nb[now]=c[r].id;        int rr=c[r].r;        if(!rr||(l&&c[p[now]].h-c[l].h<=c[rr].h-c[p[now]].h))          na[now]=c[l].id;        else          na[now]=c[rr].id;    }    if(l)      c[l].r=r;    if(r)      c[r].l=l;}void prepare(){    for(int j=1;j<=20;j++)//请注意循环次序!      for(int i=1;i<=n;i++)      {        f[i][j]=f[f[i][j-1]][j-1];        disa[i][j]=disa[i][j-1]+disa[f[i][j-1]][j-1];        disb[i][j]=disb[i][j-1]+disb[f[i][j-1]][j-1];      }}void get(ll x,int p){    da=db=0;    for(int i=20;i>=0;i--)      if(f[p][i]&&(ll)(da+db+disa[p][i]+disb[p][i])<=x)//为了以防万一      {        da+=disa[p][i];        db+=disb[p][i];        p=f[p][i];      }    if(na[p]&&da+db+disa[p][0]<=x)      da+=disa[p][0];//特判a单独走的情况}int main(){    freopen("in.txt","r",stdin);    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",&c[i].h);        c[i].id=i;    }    sort(c+1,c+n+1);    for(int i=1;i<=n;i++)    {        p[c[i].id]=i;//可以说类似于一个离散化吧        c[i].l=i-1;c[i].r=i+1;    }    c[1].l=c[n].r=0;    for(int i=1;i<=n;i++)      init(i);    for(int i=1;i<=n;i++)    {        f[i][0]=nb[na[i]];        disa[i][0]=abs(c[p[i]].h-c[p[na[i]]].h);        disb[i][0]=abs(c[p[f[i][0]]].h-c[p[na[i]]].h);    }    prepare();    scanf("%lld%d",&x,&m);    for(int i=1;i<=n;i++)    {        get(x,i);        if(db&&da*1.0/db<minx)        {            minx=da*1.0/db;            ans=i;        }    }    printf("%d\n",ans);    for(int i=1;i<=m;i++)    {        scanf("%d%lld",&t,&x);        get(x,t);        printf("%d %d",da,db);        if(i!=m)//可能是因为我脸黑,被洛谷判了too many lines才加的          printf("\n");    }    return 0;}
原创粉丝点击