zoukankan      html  css  js  c++  java
  • 【luogu 3146/3147】248/262144

    【原题题面】

    【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
    ",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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    在VS2013创建WebService并在IIS中发布和使用
    Win7下IIS由于扩展配置问题而无法提供请求的页
    webservice 部署后内网不能访问问题
    有关AlterControl控件的简单应用
    部分阉割版Win7无法正常使用TTS语音的解决办法(转载)
    等待资源时检测到死锁
    将php数组转js数组,js如何接收PHP数组,json的用法
    一个炫酷的flash网站模板
    php生成zip压缩文件的方法,支持文件和压缩包路径查找
    谷歌放弃“不作恶” Alphabet要“遵守法律互相尊重”
  • 原文地址:https://www.cnblogs.com/ve-2021/p/10968327.html
Copyright © 2011-2022 走看看