题解:Luogu_P3147 [USACO16OPEN] 262144 P

题解:Luogu_P3147 [USACO16OPEN] 262144 P

Luogu_P3147 [USACO16OPEN] 262144 P
倍增DP

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;
}
posted @ 2025-02-07 14:00  nueryim  阅读(17)  评论(0)    收藏  举报