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/

浙公网安备 33010602011771号