ABC221E(树状数组+乘法逆元)
Problem Statement
Given is a sequence of N N N integers: A A A= ( A 1 A_1 A1, A 2 A_2 A2, … \dots …, A N A_N AN)
Find the number of (not necessarily contiguous) subsequences A ′ = ( A 1 ′ , A 2 ′ , … , A k ′ ) A'=(A'_1,A'_2,\ldots,A'_k) A′=(A1′,A2′,…,Ak′) of length at least 2 2 2 that satisfy the following condition:
- A 1 ′ ≤ A k ′ A'_1 \leq A'_k A1′≤Ak′.
Since the count can be enormous, print it modulo 998244353 998244353 998244353.
Here, two subsequences are distinguished when they originate from different sets of indices, even if they are the same as sequences.
Constraints
- 2 ≤ N ≤ 3 × 1 0 5 2 \leq N \leq 3 \times 10^5 2≤N≤3×105
- 1 ≤ A i ≤ 1 0 9 1 \leq A_i \leq 10^9 1≤Ai≤109
- All values in input are integers.
题意
给你长度为 N N N的数组,问你这个数组中有多少个非下降子序列(长度至少为 2 2 2)。
思路
如果一个序列即有上升的与下降的,这样我们很难看出来怎么做。那么我们就会去考虑如果是一个非下降序列这么去求非下降子序列个数的。对于一个非下降序列
(
a
i
,
a
i
+
1
,
…
,
a
j
)
(a_i,a_{i+1},\dots,a_j)
(ai,ai+1,…,aj)来说,固定头
a
i
a_i
ai与固定尾
a
j
a_j
aj一共会有
2
j
−
i
−
1
2^{j-i-1}
2j−i−1个非下降子序列,因为中间的都只有两种选择:选,或者不选,中间的数一共有
j
−
i
−
1
j-i-1
j−i−1,因此共有
2
j
−
i
−
1
2^{j-i-1}
2j−i−1次选择。那么我们就可以枚举非下降序列的末端,然后再去枚举其非下降序列的头,乘上
2
l
e
n
−
2
2^{len-2}
2len−2,公式为
∑
j
=
1
n
∑
i
=
1
j
−
1
2
j
−
i
−
1
(
a
i
≤
a
j
)
j
为序列的末端点,
i
为序列的首端点
\sum_{j=1}^n\sum_{i=1}^{j-1}2^{j-i-1}(a_i\le a_j) \\ j为序列的末端点,i为序列的首端点
j=1∑ni=1∑j−12j−i−1(ai≤aj)j为序列的末端点,i为序列的首端点
但是我们发现上述公式实现起来的复杂度为
O
(
n
2
)
O(n^2)
O(n2),这明显会
T
T
T.
我们就可以想到树状数组,树状数组可以去查询序列中在元素左边比该元素小的元素个数,那么我们就可以将这个魔改一下,使其结点权值增加为 2 − i 2^{-i} 2−i,然后去遍历一遍就行了。
#include<bits/stdc++.h>
#define Case int t;scanf("%d",&t);while(t--)
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int M=1e6+10;
const ll mod=998244353;
char s[30];
ll a[N],b[N];
ll ans[N];
ll tr[N];
int n;
ll dp[1005][1005];
ll lowbit(ll x){
return x&(-x);
}
ll qpow(ll q,ll n){
ll res=1;
while(n){
if(n&1){
res=(res*q)%mod;
}
n>>=1;
q=(q*q)%mod;
}
return res;
}
void add(ll x,ll c){
for(ll i=x;i<=n;i+=lowbit(i)){
tr[i]+=c;
}
}
ll query(ll x){
ll ans=0;
for(ll i=x;i;i-=lowbit(i)){
ans=(ans+tr[i])%mod;
}
return ans;
}
void run(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
ll idx=unique(b+1,b+n+1)-b;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+idx,a[i])-b;
}
ll ans=0;
for(int i=1;i<=n;i++){
ans=(ans+qpow(2,i-1)*query(a[i])%mod)%mod;
add(a[i],qpow(qpow(2,mod-2),i));
}
printf("%lld\n",ans);
}
int main(){
// Case
run();
return 0;
}
道阻且长,且行且珍惜