拼接串

  1. 题意

2024湖南省赛E

题意

给出⼀个⻓度为&n&的正整数串 。现在可以把两个没有重叠的连续⼦串前后拼接起来,但是要求拼接之后的
数串中每个正整数不能出现超过 次。请问能拼接出来的符合要求的数字串的最⼤⻓度是多少。


n <= 1e6
1 <= a_i <= 18

先把所有可能的分段都记录下来,时间复杂度n*18

状压后暴力枚举子集,都没有进行状态转移,其实没有用到DP。

关键是这个枚举

for (int i = 0; i < (1 << 18); i++) {
    for (int j = i; j > 0; j = j - 1 & i) {
        ans = max(ans,f[j] + f[i^j]);
    }
}

j-1&i 可以可高效从大到小枚举子集
f[i^j]是与f[i]互补的子集
3^n 时间复杂度? 因为每一位如果仅仅是遍历而不枚举子集本来是有0和1两种情况,2^n
枚举子集的情况,1位多了一种情况,共两种:在子集中出现,没有在子集中出现,所以一位一共有三种情况。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define _ cout << "----------" << endl
//#define int ll 

void solve() {
    int n;
    cin >> n;
    vector<int> a(n+1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    vector<int> f(1 << 18);
    for (int i = 1; i <= n; i++) {
        int cnt = 0;
        for (int j = i; j <= min(n,i+18); j++) {
            if (cnt & ((1 << (a[j] - 1)))) {
                break;
            }
            cnt |= (1 << (a[j]-1));
            f[cnt] = j - i + 1;            
        }
    }
    int ans = 0;
    for (int i = 0; i < (1 << 18); i++) {
        for (int j = i; j > 0; j = j - 1 & i) {
            ans = max(ans,f[j] + f[i^j]);
        }
    }
    cout << ans << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt = 1;
    //cin >> tt;
    while (tt--) {
       solve();
    }
    return 0;
} 
github