E - LEQ
题意:
给定一个长度为
n
n
n 的序列,问有多少种子序列满足
a
1
<
=
a
k
(
1
<
=
k
<
=
n
)
a_1<=a_k(1<=k<=n)
a1<=ak(1<=k<=n)
思路:
可以发现只需要从原序列中确定首和尾,这个子序列中间的就无所谓了
设选出的
a
i
<
=
a
j
a_i<=a_j
ai<=aj,那么这一对的贡献即为
2
j
−
i
−
1
2^{j-i-1}
2j−i−1
转化问题为
∑
1
<
=
i
<
j
<
=
n
2
j
−
i
−
1
[
a
i
<
=
a
j
]
\sum_{1<=i<j<=n}2^{j-i-1}[a_i<=a_j]
1<=i<j<=n∑2j−i−1[ai<=aj]
可以发现我们不需要知道
a
i
a_i
ai 和
a
j
a_j
aj 的值具体是多少,只需要知道他们的相对大小,而且
1
<
=
a
i
<
=
1
0
9
1<=a_i<=10^9
1<=ai<=109
可以先离散化
然后就可以发现这样就变成了一个二维偏序问题
若当前枚举到
j
j
j
那么以
j
j
j 为右端点的点对贡献即为
2
j
∗
∑
1
<
=
i
<
j
2
−
(
i
+
1
)
[
a
i
<
=
a
j
]
2^j*\sum_{1<=i<j}2^{-(i+1)}[a_i<=a_j]
2j∗∑1<=i<j2−(i+1)[ai<=aj]
设
a
j
a_j
aj 离散化后的下标为
d
d
d
可以发现每次
u
p
d
a
t
e
(
d
,
1
2
(
i
+
1
)
)
update(d, \frac{1}{2^{(i+1)}})
update(d,2(i+1)1) 即可快速求出和
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int a[maxn];
vector <int> v;
ll c[maxn];
void update(int i, ll k){
while(i <= maxn) (c[i] += k) %= mod, i += i & (-i);
}
ll qry(int i){
ll ans = 0;while(i) (ans += c[i]) %= mod, i -= i & (-i);return ans;
}
ll q_pow(ll a, ll b){
ll ans = 1;while(b){
if(b & 1) ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}return ans;
}
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i){
cin >> a[i];
v.push_back(a[i]);
}
sort(all(v));
m = unique(all(v)) - v.begin();
v.erase(v.begin() + m, v.end());
ll ans = 0;
for(int i = 1; i <= n; ++i){
int d = lower_bound(all(v), a[i]) - v.begin() + 1;
(ans += q_pow(2, i) * qry(d) % mod) %= mod;
update(d, q_pow(q_pow(2, i + 1), mod - 2));
}
cout << ans;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}