ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【luogu 3146/3147】248/262144

2019-06-03 16:41:21  阅读:291  来源: 互联网

标签:ch freopen int luogu 262144 File 248 getchar


【原题题面】

【luogu 3146】248传送门

【luogu 3147】262144传送门

【题面大意】

给定一个1*N(2<=N<=248/262144) 的地图,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。

【题解】

【壹/248】

区间dp。

f[l][r]表示从l到r的合并后最大值,注意合并时必须满足f[l][k]==f[k+1][r]。

初值为f[i][i] = a[i],因为要求max所以其余赋值为-inf或0也行。

答案为每个f[l][r]取max的值。

【code1】

#include<bits/stdc++.h>
using namespace std;
#define File "248"
#define ll long long
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline int read(){
    int x=0,f=1;   char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = 2e3+3;
int n,mx;
int a[mxn];
int f[mxn][mxn];
inline int MAX(int x,int y){
    return x < y ? y : x;
}
/*
1.初值
2.循环范围
3.转移
4.答案
*/
int main(){
//    file();
    n = read();
    for(register int i = 1;i <= n; ++i) a[i] = read(),mx = MAX(mx,a[i]);
    memset(f,0,sizeof f);
    for(int i = 1;i <= n; ++i) f[i][i] = a[i];

    for(register int len = 2;len <= n; ++len){
        for(register int l = 1;l <= n-len+1; ++l){
            int r = l+len-1;
            for(register int k = l;k < r; ++k)
                if(f[l][k]==f[k+1][r]) f[l][r] = MAX(f[l][r],f[l][k]+1);
            mx = MAX(mx,f[l][r]);
        }
    }
    printf("%d\n",mx);
    return 0;
}
/*
4
1
1
1
2
*/
View Code

【贰/261244】

仔细确认发现跟前一题确确实实是一样的,n^3的区间dp当然是死翘翘了。

观察题目的特性:

序列每个数的范围极其小,所以可以考虑用它来搞一波事情。

考虑dp状态的设置:
一维是能合并出来的数字的大小
一维是下标的值
如果将f值设为能合并出来的数的大小->无法转移,不满足最优子结构

将f值设置为下标,类似倍增。
f[i][j]表示左端点为j时,能合并出的最大值为i的区间的右端点。
这样设置状态能保证往后转移。
转移:f[i][j] = f[i-1][f[i-1][j]];

初值:f[a[i]][i] = i+1;

答案:i的值。

关于58:

因为给定的原序列最大值为40,极限情况下,相邻两数的合并每次会给最大值加一,那么最多会加到58。

当然循环到59,60...什么的也没问题,如果时间复杂度过得去的话...

【code2】

#include<bits/stdc++.h>
using namespace std;
#define File "262144"
#define ll long long
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline int read(){
    int x=0,f=1;   char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
const int mxn = (1<<18)+5;
int n;
int f[63][mxn];
/*
1.转移->f[i][j] = f[i-1][f[i-1][j]]
2.循环
3.初值
4.答案
*/
int ans;
int main(){
    //file();
    n = read();
    for(int i = 1;i <= n; ++i){
        int t = read();
        f[t][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 = max(i,ans);
        }
    }
    printf("%d\n",ans);
    return 0;
}
View Code

标签:ch,freopen,int,luogu,262144,File,248,getchar
来源: https://www.cnblogs.com/ve-2021/p/10968327.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有