• 【题解】分离与合体 [Loj10151]


    【题解】分离与合体 [Loj10151]

    传送门:分离与合体 ([Loj10151])

    【题目描述】

    给定一个长度为 (n) 的序列,如果从某个点 (k) 处将区间 ([l,r]) 断开,划分为 ([l,k])([k+1,r]),可以得到 (a[k]*(a[l]+a[r])) 的分数,要求最后要把区间划分到无法再分为止(即长度全为 (1)),并按照分离时间从前到后,区间从左到右的顺序输出所有划分点 (k)

    【样例】

    样例输入:
    7
    1 2 3 4 5 6 7
    
    样例输出:
    238
    1 2 3 4 5 6
    
    

    【数据范围】

    (20\%) (N leqslant 10)

    (40\%) (N leqslant 50)

    (100\%) (N leqslant 300)


    【分析】

    与经典区间 (dp)石子合并 ([NOI1995]) ([P1880])非常相似,用 (dp[l][r]) 表示将 ([l,r]) 这段区间彻底划分完所能获得的最大分数。

    通常区间 (dp) 有两种大的方向:
    ((1).)小区间大区间转移
    ((2).)大区间小区间转移

    这道题应采用 ((1)) 更为合适。

    按区间长度从小到大枚举所有区间 ([l,r]),再枚举所有决策点 (k in[l,r-1])(dp) 方程为:
    (dp[l][r]=max{(a[l]+a[r])*a[k] + dp[l][k] +dp[k+1][r] })

    那么再来看这无比诡异的输出。
    区间最优决策点在 (dp) 的时候记录一下就可以,输出方式可以用队列来进行模拟,和 (bfs) 的过程类似。

    另外要注意这里队列的两种写法会造成空间消耗的不同,
    ((1).) 从队首取出元素后判断是否为合法区间(即长度大于 (1) 才输出划分点)
    ((2).) 在入队前判断,仅让合法区间入队。

    第二种只会在队列中加入 (n-1) 个合法区间(因为只会划分 (n-1) 次),而第一种会比第二种多加入 (n) 个长度为 (1) 的不合法区间,因此队列空间要开 (2n)

    时间复杂度为 (O(n^3))

    【Code】

    #include<cstdio>
    #define Re register int
    const int N=303;
    struct QAQ{int l,r;}Q[N];//空间要开够
    int n,h=1,t,tmp,a[N],g[N][N],dp[N][N];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    int main(){
        in(n);
        for(Re i=1;i<=n;++i)in(a[i]);
        for(Re i=2;i<=n+1;++i)
        	for(Re l=1;l+i-1<=n;++l){
                Re r=l+i-1;
                for(Re k=l;k<r;++k)
                    if((tmp=dp[l][k]+dp[k+1][r]+a[k]*(a[l]+a[r]))>dp[l][r])dp[l][r]=tmp,g[l][r]=k;
        	}
        printf("%d
    ",dp[1][n]);
        Q[++t]=(QAQ){1,n};
        while(h<=t){
        	QAQ x=Q[h++];
        	Re l=x.l,r=x.r,k=g[l][r];
    //    	if(l==r)continue;/*写法1.0*/ 
    //      if(!k)continue;/*写法1.1*/ 
        	printf("%d ",k);
    //    	Q[++t]=(QAQ){l,k};/*写法1*/ 
    //    	Q[++t]=(QAQ){k+1,r};/*写法1*/ 
            if(l<k)Q[++t]=(QAQ){l,k};/*写法2*/ 
            if(k+1<r)Q[++t]=(QAQ){k+1,r};/*写法2*/ 
        }
    }
    
  • 相关阅读:
    用CSS开启硬件加速来提高网站性能
    vim中替换内容
    alias vi=vim
    PHP 多进程初识
    端口的查看
    PHP三种终止脚本执行:return,die,exit
    2021.3.14(每周总结)
    2021.3.13
    2021.3.12
    2021.3.11
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11358800.html
Copyright © 2020-2023  润新知