BZOJ-4576: [Usaco2016 Open]262144

[文章目录]

Description

就是给你n个数,然后每次可以合并相邻两个相同的数得到一个+1的数,问最后能得到的最大的数?n<=262144,ai<=40

dp。这道题tonyzhao讲真讲过啊,但是就是不会啊。
考虑状态的设定,如果以区间两个端点+合成的数设定,空间不够,时间上感觉也不行。tonyzhao当时讲的是由于数组存的值很小,不超过40+logn,考虑将数组的第二维和表示能合成的值换一下。
状态设为f[j][i]表示以j为开头,整个区间合成一个i的右端点的值,发现很好转移。f[j][i]=f[f[j][i-1]][i-1].如果为0,则无解。

发现一个卡常数小技能:
将二维数组的第一维设为外层循环,第二维设成内层循环的话常数大概小1/3.
这道题:2732 ms : 808 ms

// 808ms
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,f[65][300000];
int ans=1,mx=1;
int main()
{
    scanf("%d",&n); int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x); mx=max(x,mx);
        f[x][i]=i+1;
    }
    for(int i=1;i<=mx;i++)
        for(int j=1;j<=n;j++)
            if(f[i][j]&&f[i][f[i][j]])
            {
                f[i+1][j]=f[i][f[i][j]];
                if(i+1>mx) mx=i+1;
            }
    printf("%d",mx);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注