Codeforces Round #531 E. Monotonic Renumeration(思维题)

题目链接

题意:
给出一个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 
#include 
#include 
#include 
#include 

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

你可能感兴趣的:(思维,codeforces)