https://vjudge.net/problem/HYSBZ-2002
7月31日 似乎是第一个 没有在家里过的生日。。。好像是真的 高中那么紧张。。。老天爷为了让我回家 都下雨把学校楼冲垮了。。。话说今天阴阳师抽卡虽然没有抽到大岳丸(正常拉)但是居然出了3黄 还是蛮开心的。。。
说说这个题吧 题目是中文题 题意很明确
解题思路 分为根号n块 统计每块内的每一个小块何时跳出这个块
我们搞两个数组 一个叫pos[]数组 一个叫times[]数组
Pos数组表明下标为这个号的这个块跳出当前块的落地点
times[]是跳出当前块(注意不是整块)要跳几次
如果Pos直接跳出整个数组(即达成目标)pos=-1;
跳出当前块 pos=i+arr[i]
否则 pos=pos[i+arr[i]]
就样例来说
4
1 2 1 1
pos 3 3 -1 -1
time 2 1 2 1
之后 根据询问 实时更新 注意是倒序更新 因为某一块的数值更新 其后面的数值不会受到影响 只会影响前面的
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <ctime>
#include <map>
#include <stack>
#include <set>
#include <cstring>
#include <sstream>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> pi;
const int maxn = 2e5 + 5;
int pos[maxn], arr[maxn], times[maxn];
int main()
{
int n, m, blocks, k, x, y, ans = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
blocks = (int)sqrt(n + 1e-7); //分为根号n块
for (int i = n - 1; i >= 0; i--)
{ //从后往前
if (i + arr[i] >= n)
{ //如果能直接跳出界外
pos[i] = -1;
times[i] = 1; //只需要一步
}
else if (i + arr[i] >= ((i / blocks) + 1) * blocks)
{ //如果能跳出当前块
pos[i] = i + arr[i]; //块外落地点
times[i] = 1;
}
else
{
pos[i] = pos[i + arr[i]]; //在块内 跳出点有一点递归的思想 就是直到跳到界外
times[i] = times[i + arr[i]] + 1;
}
}
scanf("%d", &m);
for (int i = 1; i <= m; i++)
{
scanf("%d", &k);
if (k == 1)
{
scanf("%d", &x);
ans = 0;
while (x != -1)
{
ans += times[x]; //统计步数
x = pos[x]; //直接下一块
}
printf("%d\n", ans);
}
else
{
scanf("%d%d", &x, &y);
arr[x] = y;
for (int i = x; i >= x / blocks * blocks; i--)
{ //只更新当前块中这个点之前的那部分
if (i + arr[i] >= n)
{
pos[i] = -1, times[i] = 1;
}
else if (i + arr[i] >= ((i / blocks) + 1) * blocks)
{
pos[i] = i + arr[i];
times[i] = 1;
}
else
{
pos[i] = pos[i + arr[i]];
times[i] = times[i + arr[i]] + 1;
}
}
}
}
return 0;
}







Comments | NOTHING