题解:Luogu_P3147 [USACO16OPEN] 262144 P
题解:Luogu_P3147 [USACO16OPEN] 262144 P
Solution
考虑这种合并区间的问题使用区间 DP,但 \(n\) 的范围太大没法设 \(f_{i,j}\) 表示将 \(i\sim j\) 合并为多少。
注意到能合并出的数最多为 58(\(40+log(262144)\)),于是我们将记录左右端点存值变为记录左端点和值存右端点。
状态:\(f_{i,j}\) 表示以 \(i\) 为左端点,合并为 \(j\) 的区间右端点下标+1(方便转移)
边界:\(f_{i,a[i]}=i+1\)
转移:\(f_{i,j}=f_{f_{i,j-1},j-1}\)(有点像倍增)
Code
//P3147
#include <iostream>
#include <cstdio>
using namespace std;
int read()
{
int val = 0;
bool si = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
si ^= ch == '-';
for (; isdigit(ch); ch = getchar())
val = (val << 3) + (val << 1) + (ch ^ 48);
return si ? - val : val;
}
const int N = 262145;
int n, ans, f[N][60];
int main()
{
n = read();
for (int i = 1; i <= n; i ++)
f[i][read()] = i + 1;
for (int j = 2; j <= 58; j ++)
for (int i = 1; i <= n; i ++)
{
if (f[i][j] == 0)
f[i][j] = f[f[i][j - 1]][j - 1];
if (f[i][j] != 0)
ans = j;
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号