• 合并集合


    点击跳转

    区间dp问题

    有n个集合,第i个集合记为Si,集合按环状排列,即第i+1个集合右边是第ii个集合,第n个集合右边是第ii个集合。

    一开始每个集合里只有一个数,每次你可以选择两个相邻的集合S,T然后合并成S∪T,之后你可以获得收益|S|×|T|,其中|S|表示集合S的元素个数。

    你需要一直进行以上的操作直到只剩一个集合为止,求能获得的最大的收益之和。

    断环为链,复制两倍区间DP。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=310;
    int a[N]; 
    int sum[N][N];
    int f[N][N];
    bitset<N> cnt;
    signed main() {
    	int n;
        cin >> n;
        for (register int i = 1; i <= n; ++i) cin >> a[i];
        for (register int i = 1; i <= n; ++i) a[i + n] = a[i];
        for (register int len = 1; len <= n; ++len) {
            for (register int l = 1, r = len + l - 1; r <= 2 * n; ++l, ++r) {
                cnt.reset();//初始化置为0
                for (register int i = l; i <= r; ++i) cnt[a[i]] = 1;
                sum[l][r] = cnt.count();
                //			cerr << l << " " << r << " " << sum[l][r] << endl;
            }
        }
        for (register int len = 2; len <= n; ++len) {
            for (register int l = 1, r = l + len - 1; r <= 2 * n; ++l, ++r) {
                for (register int k = l; k < r; ++k) {
                    f[l][r] = max(f[l][r], f[l][k] + f[k + 1][r] + sum[l][k] * sum[k + 1][r]);
                }
            }
        }
        int ans = 0;
        for (register int i = 1; i <= n; ++i) ans = max(ans, f[i][i + n - 1]);
        cerr << ans << endl;
    }
    
    
  • 相关阅读:
    oracle 分配表权限给用户的写法
    任务的一种写法:
    解决oracle 32位64位的问题
    设计模式学习
    Nginx 相关介绍
    (2) html 语义化
    (1)HTML5的常用新特性你必须知道
    less初学手记
    如何修改chrome记住密码后自动填充表单的黄色背景 ?
    HTML的水平居中和垂直居中解决方案
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/13582650.html
Copyright © 2020-2023  润新知