주제 :
분석 :
질문의 의미에 따라, 단지 가장 긴 서브는 각 번호 상승 순서 이후 가장 긴 길이의 반을 찾을 수 있습니다 상승 각 번호와 공헌의 가장 긴 상승 수의 서브 시퀀스의 수를 찾을 필요가 있지만, 이것은 좋지 않다 수량 통계; 간주 DP는 DP 정의 [I]는 최종 시퀀스 번호의 i 번째 상승의 가장 긴 길이가 상기 DP가 [I]가 용이 수에 대한 방정식 전송할 발생 : DP [I] = 최대 {(DP)를 [J , 0 <J <난 [J를 &&] <A [I]} + 1, DP [I] = 합 {DP [J], 0 <j는 <내가 && DP가 [j]가 DP가 = [I] -1 각 지점을 통해 찾을 수 있습니다, 다시 그것에서 오는 다음과}, 세그먼트 트리 유지 보수 간격과 최대 수를 신속하게 전달 될 수는 접두사 쿼리를 때마다, 당신은 또한 펜윅 트리 유지 보수를 사용할 수 있습니다 서브 시퀀스의 길이 및 수의 최대 상승
코드 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
const int maxn = 5e5+55;
struct node{
LL len,num;
}tr[maxn];
int n,m,a[maxn],c[maxn];
node pre[maxn],cur[maxn];
inline int lowbit(int x){
return x&(-x);
}
void add(int x,node e){
while(x <= m){
if(tr[x].len == e.len) tr[x].num = (tr[x].num+e.num)%mod;
else if(tr[x].len < e.len){
tr[x].len = e.len;
tr[x].num = e.num;
}
x += lowbit(x);
}
}
node query(int x){
node res = {0,0};
while(x > 0){
if(res.len == tr[x].len) res.num = (res.num+tr[x].num)%mod;
else if(res.len < tr[x].len){
res.len = tr[x].len;
res.num = tr[x].num;
}
x -= lowbit(x);
}
return res;
}
LL qpow(LL a,LL x){
LL res = 1;
while(x){
if(x&1) res = res * a % mod;
a = a * a % mod;
x >>= 1;
}
return res;
}
int main(){
cin >> n;
for(int i = 0;i < n; ++i) cin >> a[i],c[i] = a[i];
sort(c,c+n); m = unique(c,c+n) - c;
for(int i = 0;i < n; ++i) a[i] = lower_bound(c,c+m,a[i])-c+1;
for(int i = 0;i < n; ++i){
pre[i] = query(a[i]-1);
if(++pre[i].len == 1) pre[i].num = 1;
add(a[i],pre[i]);
}
for(int i = 0; i < n; ++i) a[i] = m-a[i]+1; //反转序号,方便树状数组更新和查询
memset(tr,0,sizeof(tr));
node ans = {0,0}; //整个数组的最长上升子序列的长度及数量
for(int i = n-1; ~i; --i){
cur[i] = query(a[i]-1);
if(++cur[i].len == 1) cur[i].num = 1;
add(a[i],cur[i]);
if(ans.len == cur[i].len) ans.num = (ans.num + cur[i].num)%mod;
else if(ans.len < cur[i].len) ans = cur[i];
}
LL inv = qpow(ans.num,mod-2);
for(int i = 0;i < n; ++i){
if(pre[i].len+cur[i].len==ans.len+1) {
printf("%lld ",pre[i].num*cur[i].num%mod*inv%mod);
}
else printf("0 ");
}
return 0;
}