1280 前缀后缀集合
- 1.0 秒
- 131,072.0 KB
- 40 分
- 4级题
一个数组包含N个正整数,其中有些是重复的。一个前缀后缀集是满足这样条件的下标对(P,S), 0<= P,S < N 满足数组元素A[0..P]的值也在A[S..N - 1]的值中出现,并且A[S..N - 1]中的值也再A[0..P]中出现。换句话说前缀的集合A[0..P]与后缀集合A[S..N - 1]包含完全相同的值。求这样的前缀后缀集合的数量。
例如:3 5 7 3 3 5,共有14个集合符合条件:(1, 4), (1, 3), (2, 2), (2, 1), (2, 0), (3, 2), (3, 1), (3, 0), (4, 2), (4, 1), (4, 0), (5, 2), (5, 1), (5, 0)
本题由 @javaman 翻译。
收起
输入
<span style="color:#676a6c"><span style="color:#333333">第1行:一个数N, 表示数组的长度(1 <= N <= 50000)。
第2 - N + 1行:每行1个数,对应数组中的元素Ai。(1 <= Ai <= 10^9)</span></span>
输出
<span style="color:#676a6c"><span style="color:#333333">输出符合条件的集合数量。</span></span>
输入样例
<span style="color:#676a6c"><span style="color:#333333">6
3
5
7
3
3
5</span></span>
输出样例
<span style="color:#676a6c"><span style="color:#333333">14</span></span>
此题如果用Hash来做的话,需要将按照顺序将映射,我暴力+set写了一发,T了四个点。
网上有一篇,但迷之hash,没看到Hash是如何用的,只知道他实现了集合的hash对应。
或者用map模拟一下,直接看代码,有注释。
集合Hash
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int M =1e5 + 50;
#define mst(a,b) memset(a,b,sizeof(a))
#define rush() int T;cin>>T;while(T--)
map<int,bool> mp;
map<pair<int,int>,int> pre;
int a[M];
int main()
{
int n,k = 0,kk = 0;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(mp[a[i]] == 0)
{
k = k + a[i] * 131 % mod;
kk = kk + a[i] % mod * a[i] % mod;
mp[a[i]] = 1;
}
pre[ {k,kk}]++;
}
mp.clear();
k = kk = 0;
long long ans = 0;
for(int i=n; i>=1; i--)
{
if(mp[a[i]] == 0)
{
k = k + a[i] * 131 % mod;
kk = kk + a[i] % mod * a[i] % mod;
mp[a[i]] = 1;
}
ans += pre[ {k,kk}];
}
cout<<ans;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int n,a[N];
LL ans;
map<int,int> mp;
void solve()
{
int r=n;
LL temp=0,num=0;//temp前i个字符已经匹配的数量,num两边差别的数量
for(int i=1;i<=n;i++)
{
if(mp[a[i]]!=0) //前面的字符已经出现了,说明前面的集合不变,直接累加前面的答案即可
{
ans+=temp;
}
else //该字符没有出现,前缀集合改变,后缀集合也需要改变,temp清0
{
mp[a[i]]=1;
temp=0;
num++;
while(r>=1&&mp[a[r]]!=0)
{
if(mp[a[r]]==1)
{
mp[a[r]]=2;
num--;
}
if(num==0)
{
ans++;
temp++;
}
r--;
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
solve();
printf("%lld\n",ans);
}
T了四个点
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=1000005;
const int P=131;
ULL hashv_pre[N],hashv_suff[N],power[N];
int n,a[N];
LL ans=0;
void calHash()
{
map<int,int> mp;
set<int> set_pre;
map<ULL,int> hash_mp;
for(int i=1; i<=n; i++)
{
if(mp[a[i]]==0)
{
set_pre.insert(a[i]);
ULL s=0;
for(auto item:set_pre)
{
s=s*P+item;
}
hashv_pre[i]=s;
hash_mp[hashv_pre[i]]++;
mp[a[i]]++;
}
else
{
hashv_pre[i]=hashv_pre[i-1];
hash_mp[hashv_pre[i]]++;
}
}
set<int> set_suff;
mp.clear();
for(int i=n; i>=1; i--)
{
if(mp[a[i]]==0)
{
set_suff.insert(a[i]);
ULL s=0;
for(auto item:set_suff)
{
s=s*P+item;
}
hashv_suff[i]=s;
//cout<<"#"<<hashv_suff[i]<<endl;
ans+=hash_mp[hashv_suff[i]];
mp[a[i]]++;
}
else
{
hashv_suff[i]=hashv_suff[i+1];
//cout<<hashv_suff[i]<<endl;
ans+=hash_mp[hashv_suff[i]];
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
calHash();
printf("%lld\n",ans);
}