Atcoder abc 221 E - LEQ

原题链接:E - LEQ

思路:

题目要求对于从数组1~n找出所有符合开头数字小于等于结尾数字的子序列,\(A' = (A_1', A_2', ... , A_k')\),满足\(A_1' \leq A_k'\),很显然,我们只需要找到任何一对\(a_i \leq a_j\)数对,然后它的贡献是\(2^{j -i - 1}\),我们可以两重循环很容易做到,但是很明显数据范围不允许,这时候考虑,将\(2^{j -i - 1}\)变成\(\cfrac{2^{j - 1}}{2^i}\),那么答案就是\(\sum\limits_{j = 1}^N 2^{j - 1} * B_j\),其中\(B_j\)\(\sum\limits_{1 \leq i < j, a[i] <= a[j]} \cfrac{1}{2^i}\),对于\(2^{j - 1}\)可以直接用快速幂求解,而对于\(B_j\)我们可以直接用树状数组进行维护,这样复杂度就由\(O(n^2)\)优化为了\(O(NlogN)\),又由于涉及取模,因为除法不能直接取模,所以求\(2^i\)的逆元即可。

哦对了,由于使用树状数组,所以先离散化一下。

// Problem: E - LEQ
// Contest: AtCoder - AtCoder Beginner Contest 221
// URL: https://atcoder.jp/contests/abc221/tasks/abc221_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

typedef long long LL;

using namespace std;
const int N = 3E5 + 10, Mod = 998244353;
LL tr[N];
int a[N], n;
vector<int> alls;

LL lowbit(LL x) {
	return x & -x;
}

void modify(int x, LL v) { //从下往上加
	for (;x < N; x += lowbit(x)) tr[x] = (tr[x] + v) % Mod;
}

LL query(int x) {
	LL res = 0;
	for (;x ; x -= lowbit(x)) res = (res + tr[x]) % Mod;
	return res;
}

LL qpow(LL a, LL b, LL Mod) {
	LL res = 1;
	while (b) {
		if (b & 1) res = res * a % Mod;
		a = a * a % Mod;
		b >>= 1;
	}
	return res;
}

int find(int x) {
	return lower_bound(alls.begin(), alls.end(), x) - alls.begin() + 1;
}

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		alls.push_back(a[i]);
	}
	
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	
	LL res = 0;
	for (int i = 1; i <= n; i++) {
		int x = find(a[i]);
		res = (res + qpow(2, i - 1, Mod) * query(x) % Mod) % Mod;
		
		LL t = qpow(2, i, Mod);
		modify(x, qpow(t, Mod - 2, Mod));
	}
	
	cout << res << endl;
	
    return 0;
}
posted @ 2021-10-06 19:57  Xxaj5  阅读(107)  评论(0编辑  收藏  举报