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; }