bzoj 2093 [ Poi 2010 ] Frog —— 滑动窗口 + 倍增

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2093

先处理出每个点第一次会跳到哪里;

开一个长度为 K+1 的窗口(因为第一近的实际是自己),那么只会跳到左端点或右端点;

然后根据左右端点到下一个位置的距离,调整窗口位置;

然后就可以倍增跳了!

但需要微妙地卡一卡时间,可以边处理 m 算答案边倍增,然后就能过了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1e6+5;
int n,K,l,r/*,f[maxn][65]*/,f[maxn],mx,ans[maxn],tmp[maxn];
ll m,d[maxn];
ll abb(ll x){return x>0?x:-x;}
ll rd()
{
    ll ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
int main()
{
    n=rd(); K=rd(); m=rd(); K++;
    ll tt=m; while(tt)mx++,tt/=2;
    for(int i=1;i<=n;i++)d[i]=rd();
    l=1; r=K;
    for(int i=1;i<=n;i++)
    {
        while(abb(d[r+1]-d[i])<abb(d[i]-d[l])&&r<n)r++,l++;
        if(abb(d[i]-d[l])>=abb(d[r]-d[i]))f[i]=l; else f[i]=r;
    }
//    for(int j=1;j<=mx;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++)
//    {
//        ll t=0; int x=i;
//        for(int j=mx;j>=0;j--)
//            if(t+(ll)(1ll<<j)<=m)t+=(ll)(1ll<<j),x=f[x][j];
//        printf("%d ",x);
//    }
    for(int i=1;i<=n;i++)ans[i]=i;
    while(m)
    {
        if(m&1)
        {
            for(int i=1;i<=n;i++)tmp[i]=f[ans[i]];
            for(int i=1;i<=n;i++)ans[i]=tmp[i];
        }
        for(int i=1;i<=n;i++)tmp[i]=f[f[i]];
        for(int i=1;i<=n;i++)f[i]=tmp[i];
        m>>=1;
    }
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    return 0;
}

 

posted @ 2018-08-16 20:32  Zinn  阅读(237)  评论(0编辑  收藏  举报