BZOJ2093: [Poi2010]Frog
此题倍增比较好想
找第 k 近的点感觉不是很好想
没有想到啊——
两个指针扫维护里当前点最近的 k + 1 个点, +1 是因为还要算上当前点
考虑当 i + 1 时 l,r 的移动,为了保证最小,要把右端点+1的点和左端点进行比较,
若 pos[r + 1] - pos[i] < pos[i] - pos[l],就平移整个区间
此时可以选择倍增,需要滚动数组,就每次倍增的时候不断更新
ans[i] 表示从第 i 个点出发,当前跳到了 ans[i], 每次更新跳了 2^i 跳到哪
总共更新 log(m) 次就好了
或者跑个置换(?)快速幂就好了
听说以后polya要用就当板子写的
感觉思想和倍增差不多?
在 BZOJ 上加了输优才过。。。
比倍增还慢。。
代码:
快速幂:
#include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> using namespace std; typedef long long ll; const int MAXN = 1000005; int n, k; ll m, pos[MAXN]; struct TRN{ int arr[MAXN]; int& operator [] (int x) { return arr[x]; } void operator *= (TRN &b) { static TRN tmp; for(int i = 1; i <= n; ++i) tmp[i] = b[arr[i]]; memcpy(this, &tmp, sizeof(TRN)); return; } }to, ans; inline int rd() { register int x = 0; register char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } inline ll rdll() { register ll x = 0ll; register char c = getchar(); register bool f = false; while(!isdigit(c)) { f = (c == '-'); c = getchar(); } while(isdigit(c)) { x = x * 10ll + (c ^ 48); c = getchar(); } return f ? -x : x; } inline void write(int x) { register int y = 10, len = 1; while(y <= x) {y *= 10; ++len;} while(len--) {y /= 10; putchar(x / y + 48); x %= y;} return; } inline void fastpow(TRN &t, ll top) { while(top) { if(top & 1ll) ans *= t; t *= t; top >>= 1; } return; } int main() { n = rd(); k = rd(); m = rdll(); for(int i = 1; i <= n; ++i) pos[i] = rdll(); int l = 1, r = k + 1; for(int i = 1; i <= n; ++i) { while((r < n) && (pos[r + 1] - pos[i] < pos[i] - pos[l])) {++l; ++r;} to[i] = ((pos[i] - pos[l] >= pos[r] - pos[i]) ? (l) : (r)); ans[i] = i; } fastpow(to, m); for(int i = 1; i < n; ++i) { write(ans[i]); putchar(' '); } write(ans[n]); putchar('\n'); return 0; }
倍增:
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cctype> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; const int MAXN = 1000005; int n, k, lg; int to[2][MAXN], ans[MAXN]; ll m, pos[MAXN], pwr[70]; inline int rd() { register int x = 0; register char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } inline ll rdll() { register ll x = 0ll; register char c = getchar(); register bool f = false; while(!isdigit(c)) { f = (c == '-'); c = getchar(); } while(isdigit(c)) { x = x * 10ll + (c ^ 48); c = getchar(); } return f ? -x : x; } int main() { n = rd(); k = rd(); m = rdll(); lg = log2(m) + 1; pwr[0] = 1ll; for(int i = 1; i <= lg; ++i) pwr[i] = (pwr[i - 1] << 1); for(int i = 1; i <= n; ++i) pos[i] = rdll(); int l = 1, r = k + 1; for(int i = 1; i <= n; ++i) { while(r < n && pos[r + 1] - pos[i] < pos[i] - pos[l]) {++l; ++r;} to[0][i] = ((pos[i] - pos[l] >= pos[r] - pos[i]) ? (l) : (r)); } if(m & 1) for(int i = 1; i <= n; ++i) ans[i] = to[0][i]; else for(int i = 1; i <= n; ++i) ans[i] = i; int cur = 1; for(int i = 1; i <= lg; ++i) { for(int j = 1; j <= n; ++j) to[cur][j] = to[cur ^ 1][to[cur ^ 1][j]]; if((m & pwr[i])) for(int j = 1; j <= n; ++j) ans[j] = to[cur][ans[j]]; cur ^= 1; } for(int i = 1; i < n; ++i) printf("%d ", ans[i]); printf("%d\n", ans[n]); return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/