合并集合

点击跳转

区间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;
}

posted @ 2020-08-29 16:40  邦的轩辕  阅读(234)  评论(0编辑  收藏  举报