1 条题解

  • 0
    @ 2025-8-24 21:45:48

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 3493441984zz
    **

    搬运于2025-08-24 21:45:48,当前版本为作者最后更新于2019-02-01 18:46:20,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    动态规划

    其实这题很简单,但是我就是看了题解。。。

    这篇题解的思路和其他dalaodalao的大同小异,但是这篇主要解释了5858这个神奇的数字,以及状态转移方程的意思


    状态

    我们定义f[i][j]f[i][j],里面存的值是左端点为jj,能合并出ii这个数字的右端点的位置

    那么状态转移方程如下:

    f[i][j]=f[i1][f[i1][j]]f[i][j]=f[i-1][f[i-1][j]]

    为什么呢?

    其实这就有点倍增的味道了,我们首先(没有图,自行脑补或者参考其他人的题解qwqqwq

    我们先在脑海中画一个数轴qwqqwq

    然后最左边的一个点位置为jj

    那么我们可以求出f[i1][j]f[i-1][j],也就是从jj往后一直合并到哪个位置,可以最终合并出i1i-1,这个位置其实就是f[i1][j]f[i-1][j]

    那么我们接下来呢?

    我们从这个位置继续向后,看看到哪个位置又能合并出一个i1i-1,那么找到这个点,其实就是f[i1][f[i1][j]]f[i-1][f[i-1][j]],我们合并到这里的时候,就会合并出两个相邻的i1i-1,那么不就可以合并出一个ii了吗?

    所以,状态转移就是$$f[i][j]=f[i-1][f[i-1][j]]$$

    接下来是美滋滋的代码时间~~~

    #include<iostream>
    #include<cstdio>
    #define N 61
    #define M 270007
    using namespace std;
    int n,ans;
    int f[N][M];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
    	{
    		int in;
    		scanf("%d",&in);
    		f[in][i]=i+1;
    	}
        for(int i=2;i<=58;++i)//58?????
            for(int j=1;j<=n;++j)
            {
                if(!f[i][j]) 
    				f[i][j]=f[i-1][f[i-1][j]];
                if(f[i][j]) 
    				ans=i;
            }
        printf("%d",ans);
    }
    

    那么上面这个神奇的5858呢?

    其实就跟数据范围有关

    我们看到2N2621442≤N≤262144,而我们像倍增一样合并,那么因为218=2621442^{18}=262144

    而数字的大小在1401-40之间,那么产生的数最多也就是40+18=5840+18=58


    如果有错误,请私信我或者评论留言~~(而我不会看)~~

    • 1

    信息

    ID
    2211
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者