P3146 [USACO16OPEN]248 & P3147 [USACO16OPEN]262144

注:两道题目题意是一样的,但是数据范围不同,一个为弱化版,另一个为强化版。

 

P3146传送门(弱化版) 

 

思路:

  区间动规,设 f [ i ][ j ] 表示在区间 i ~ j 中获得的最大值,与普通区间动规最大的不同在于:只有左区间的最大值等于右区间的最大值时才能够进行转移。

 

AC代码: 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define maxn 257
int n;
int maxx=-0x3f;//maxx记录合并后的最大值 
int f[maxn][maxn];//f[i][j]表示 i~j 区间内合并后的最大值
inline int read()
{
    char kr=0;
    char ls;
    for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
    int xs=0;
    for(;ls>='0'&&ls<='9';ls=getchar())
    {
        xs=xs*10+ls-48;
    }
    if(kr=='-') xs=0-xs;
    return xs;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        f[i][i]=read();
        maxx=max(f[i][i],maxx);
    }
    for(int i=2;i<=n;i++)// i 枚举区间长度 
    {
        for(int j=1;j+i-1<=n;j++)//枚举左端点 
        {
            int r=i+j-1;//计算出右端点 
            for(int k=j;k<r;k++)//枚举断点 
            {
                if(f[j][k]==f[k+1][r])//如果断点的左右两边最大值相等,转移 
                {
                    f[j][r]=max(f[j][r],f[j][k]+1);
                    maxx=max(maxx,f[j][r]);//记录最大值 
                }
            }
        }
    }
    printf("%d
",maxx);//输出 
return 0;
}

P3147传送门(强化版)

 

思路:

  在数据范围 2~262144 的情况下,使用区间动规在空间和时间上就有点吃不消了。这是我们考虑更加优化的动规,可以设 f [ i ][ j ] 表示从 j 开始合并到 i 这个数字序列的末尾的下标是什么。那么因为合并的总是一段连续的区间,就有 f [ i ][ j ] = f [ i-1 ][ f [ i-1 ][ j ] ];

 

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define maxn 300000
int n,a;
int ans=-0x3f;
int f[60][maxn]; 
inline int read()
{
    char kr=0;
    char ls;
    for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
    int xs=0;
    for(;ls>='0'&&ls<='9';ls=getchar())
    {
        xs=(xs<<3)+(xs<<1)+ls-48;
    }
    if(kr=='-') xs=0-xs;
    return xs;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a=read();
        f[a][i]=i+1;
    }
    for(int i=2;i<=58;i++)
    {
        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);
return 0;
}
原文地址:https://www.cnblogs.com/lck-lck/p/9670512.html