题意:
给出一个a数组,让你构建b数组,要求满足下列条件:
- b1=0;
- for every pair of indices i and j such that 1≤i,j≤n, if ai=aj, then bi=bj (note that if ai≠aj, it is still possible that bi=bj);
- for every index i∈[1,n−1] either bi=bi+1 or bi+1=bi+1.
最后要求的是组成b数组的方案数目
思路:
首先要注意到两个相同的数之间的数一定相同,我们把整个a数组分成若干块,每块之间满足b[i] = b[i + 1]或者b[i] + 1 == b[i + 1],每块内部全都要一致。至于怎么分成若干块,显然,单独看一个数,从这个数出现开始,到这个数最后一次出现的位置之间肯定是要看成是一块的。从某种程度上来说,每个数代表了一个区间,我们要把所有有交集的区间并起来作为一个块。举个例子来说明一下:假如 a = {1, 2, 1, 3, 3, 2, 4, 4, 7},那么就可以分成两块分别是{1, 2, 1, 3, 3, 2}, {4, 4, 7},解释一下,很显然两个1肯定要放在一块内,二者之间还夹了一个2,所以数字2的区间要和数字1的区间合并在一起,就成了{1, 2, 1, 3, 3, 2}。求出块数,因为第一块已经定了,为0(因为题目规定b[1] = 0),所以说第一块的情况为一种,其余的每块都有两种情况,所以最终的答案就是2x-1中情况(其中x代表块数)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 2 * 1e5 + 100;
const ll mod = 998244353;
int n;
int a[maxn];
int overpos[maxn];
map < int, int > ma;
ll qpow(ll a, ll b) { //快速幂取模
ll res = 1;
while(b) {
if(b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
cin >> n;
for(int i = 1; i <= n; ++ i) {
scanf("%d", &a[i]);
}
for(int i = n; i >= 1; i --) { //求出每个a[i]出现的最后位置,也就是从后往前第一次出现的位置
if(ma.find(a[i]) == ma.end()) {
ma[a[i]] = i;
}
overpos[i] = ma[a[i]];
}
int begins = 1;
ll ans = 0;
while(begins <= n) {
ans++;
int en = overpos[begins];
for(int i = begins; i <= overpos[en] && i <= n; ++ i) { //注意跳出循环的条件,数组下标是en
en = max(en, overpos[i]);
}
begins = en + 1;
}
ll cnt = qpow(2, ans - 1);
cout << cnt << endl;
return 0;
}