1. 程式人生 > >【noip 2012】開車旅行

【noip 2012】開車旅行

12年的神題啊寫了2天
50 分鐘一個n^2預處理的暴力 拿了70分
感覺價效比挺高的
縣貼個程式碼

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define inf 0x3fffffff
using namespace std;
//by mars_ch
int n,m;
int min1,min2;
struct data
{
    int h,id;
}c[1000005];
int nexta[1000005],nextb[1000005],s;
int disa[100005
]; int disb[100005]; int x0; void dfs(int st,int x,int suma,int sumb,int p,int z) { if(p == 1) //a { if(suma+sumb+abs(c[x].h-c[nexta[x]].h)>z || nexta[x] == 0) { disa[st]=suma; disb[st]=sumb; return ; } suma+=abs(c[x].h-c[nexta[x]].h); dfs(st,nexta[x],suma,sumb,2
,z); } else { if(suma+sumb+abs(c[x].h-c[nextb[x]].h)>z || nextb[x] == 0) { disa[st]=suma; disb[st]=sumb; return ; } sumb+=abs(c[x].h-c[nextb[x]].h); dfs(st,nextb[x],suma,sumb,1,z); } } int main() { scanf
("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&c[i].h); } for(int i=1;i<=n;i++) { min1=inf,min2=inf; for(int j=i+1;j<=n;j++) { if(abs(c[i].h-c[j].h)<min1) { min2=min1; nexta[i]=nextb[i]; min1=abs(c[i].h-c[j].h); nextb[i]=j; } else if(abs(c[i].h-c[j].h)<min2 && abs(c[i].h-c[j].h)!=min1) { min2=abs(c[i].h-c[j].h); nexta[i]=j; } else if(abs(c[i].h-c[j].h) == min1 && c[j].h>c[nextb[i]].h) { min2=min1; nexta[i]=j; } else if(abs(c[i].h-c[j].h) == min1 && c[j].h<c[nextb[i]].h) { min2=min1; nexta[i]=nextb[i]; nextb[i]=j; } } } /*for(int i=1;i<=n;i++) { printf("%d %d\n",nexta[i],nextb[i]); }*/ scanf("%d",&x0); /*************第一問************/ double ans=1.0*0x3fffffff; double res=0.0; for(int k=1;k<=n;k++) { dfs(k,k,0,0,1,x0); if(disb[k] == 0) res=1.0*0x3fffffff; else res=1.0*disa[k]/disb[k]; if(res<ans) { ans=res; s=k; } } printf("%d\n",s); /***************第二問*****************/ memset(disa,0,sizeof(disa)); memset(disb,0,sizeof(disb)); int ss,xx; scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d%d",&ss,&xx); memset(disa,0,sizeof(disa)); memset(disb,0,sizeof(disb)); dfs(ss,ss,0,0,1,xx); printf("%d %d\n",disa[ss],disb[ss]); } }

中間 就一個小細節 就是 注意 精度問題 所以建議除數的時候改成乘法

但是突然想到了個問題:好像沒有處理 第一問如果相等時的 海拔高點啊
資料很巧妙啊。。。也挺好改的吧 加上一個判等於,記錄一下前驅ok?

然後思考正解 其實 lyd講過所以知道 set加 倍增。

set很神奇啊 一個自己維護奇奇怪怪的結構體,但是很好用。對於這道題只用找左邊兩個右邊兩個 比較一下就ok嗯
倍增不說啥了
mark long long 的神奇輸出

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<iostream>
#define maxn 100005
using namespace std;
//by mars_ch
int n;
int disa[maxn][20],disb[maxn][20],f[maxn][20];
int nexta[maxn],nextb[maxn];
struct city
{
    int pos,h;
    bool operator < (const city &b) const{
        return h<b.h;
    }
}c[maxn];
struct data
{
    int pos,dif;
    bool operator <  (const data &b) const
    {
        if(dif!=b.dif) return dif<b.dif;
        return c[pos].h<c[b.pos].h;
    }
}t[6];
int read()
{
    int s=0,f=1;
    char p=getchar();
    while((p<'0' || p>'9') && p!='-') p=getchar();
    if(p == '-') f=-1,p=getchar();
    while(p>='0' && p<='9') s=s*10+p-'0',p=getchar();
    return f*s;
}
set<city> s;
inline void query(int St, int X,long long &ta,long long &tb)  
    {  
        for (int i = 18; ~i; -- i) 
        if (f[St][i] && disa[St][i] + disb[St][i] <= X) 
        {  
            ta += disa[St][i]; tb =tb+ disb[St][i];  
            //cout<<"XXX"<<tb<<" "<<disb[St][i]<<endl;
            X -= disa[St][i] + disb[St][i]; St = f[St][i];  
        }  
        //cout<<"asdasd  "<<tb<<endl;
        int posa = nexta[St]; if (!posa) return;  
        int dis = abs(c[posa].h - c[St].h); if (dis <= X) ta += dis;  
    }     
void find(int x)
{
    set<city> :: iterator it=s.find(c[x]);
    int tot=0;
    if(it!=s.begin())
    {
        --it;t[++tot]=(data){it->pos,abs(it->h-c[x].h)};
        if(it!=s.begin())
        {
            --it;t[++tot]=(data){it->pos,abs(it->h-c[x].h)};++it;
        }
        ++it;
    }
    if((++it)!=s.end())
    {
        t[++tot]=(data){it->pos,abs(it->h-c[x].h)};
        if((++it)!=s.end())
        {
            t[++tot]=(data){it->pos,abs(it->h-c[x].h)};--it;
        }
        --it;
    }
    sort(t+1,t+tot+1);
    nextb[x]=t[1].pos;
    if(tot==1) return;
    nexta[x]=t[2].pos;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        c[i].h=read();
        c[i].pos=i;
    }
    for(int i=n;i>=1;i--)
    {
        s.insert(c[i]);
        if(i!=n)find(i);
    }
    for(int i=1;i<=n;i++)
    {
        int p1=nexta[i],p2=nextb[nexta[i]];
        disa[i][0]=p1?abs(c[i].h-c[p1].h):0;
        disb[i][0]=p2?abs(c[p2].h-c[p1].h):0;
        f[i][0]=p2;
    }
    for(int j=1;j<=18;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];
        }   
    }

        int x0=read();
        int ans = 0;  
        long long ansa = 1e15, ansb = 0ll;  
        for (int i = 1; i <= n; ++ i) {  
            long long ta = 0, tb = 0; 
            query(i, x0,ta,tb);  
        //  cout<<"11111 "<<tb<<endl;
            //printf("   %d   %d   \n",ta,tb);
            if (tb && (!ans || ansa * tb > ansb * ta)) {  
                ansa = ta; ansb = tb; ans = i;  
            }  
        }  
        printf("%d\n",ans);
    /****************第二問********/
    int m;
    m=read();
    for(int i=1;i<=m;i++)
    {
        int ss=read(),xx=read();
        long long ta=0,tb=0;
        query(ss,xx,ta,tb);
//      cout<<ta<<" "<<tb<<endl;
        printf("%lld %lld\n",ta,tb);
     } 
}