b_51_前缀后缀集合(暴力前后缀哈希 / 双指针+双哈希)

求数组中前后缀可互相包含的集合对的数量

#include<bits/stdc++.h>
#define rep1(i,s,e) for(register int i=s;i<=e;i++)
#define rep2(i,e,s) for(register int i=e;i>=s;i--)
using namespace std;
typedef long long ll;
const int N=5e4+5;
ll n,ans,a[N];
bool chk1(unordered_set<int>& s1, unordered_set<int>& s2) {
    for (int x : s2) if (s1.find(x)==s1.end()) return false;
    return true;
}
bool chk2(unordered_set<int>& s1, unordered_set<int>& s2) {
    for (int x : s1) if (s2.find(x)==s2.end()) return false;
    return true;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n; rep1(i,1,n) cin>>a[i];
    unordered_map<int, unordered_set<int>> m1,m2;
    rep1(i,1,n) rep1(j,1,i) m1[i].insert(a[j]);
    rep2(i,n,1) rep1(j,i,n) m2[i].insert(a[j]);
    
    rep1(i,1,n)
    rep1(j,1,n) {
        auto& s1=m1[i], &s2=m2[j];
        if (chk1(s1,s2) && chk2(s1,s2)) ans++; 
    }
    cout<<ans;
    return 0;
}

看了下最优解,其实不那么容易想到

#include<bits/stdc++.h>
#define rep1(i,s,e) for(register int i=s;i<=e;i++)
using namespace std;
typedef long long ll;
const int N=5e4+5;
ll n,ans,a[N],mp[N];
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n; rep1(i,0,n-1) cin>>a[i];

    unordered_set<int> ls, rs;
    for (int l=0,r=n-1; l<n; l++) {
        ls.insert(a[l]);
        while (r>=0 && ls.find(a[r])!=ls.end()) { //ls包含右集合,
            rs.insert(a[r--]);
            mp[rs.size()]++;
        }
        ans+=mp[ls.size()]; //但累加时之类家ls中有的,因为rs可能很大,我只以ls为基准
    }
    cout<<ans;
    return 0;
}
posted @ 2020-10-25 18:50  童年の波鞋  阅读(112)  评论(0编辑  收藏  举报