2,019m 마늘 도로 재대 결 A : Michale 교사가 팬더를 설정] [펜윅 나무 + DP

주제 :

여기에 주제 ~ ~ ~

분석 :

질문의 의미에 따라, 단지 가장 긴 서브는 각 번호 상승 순서 이후 가장 긴 길이의 반을 찾을 수 있습니다 상승 각 번호와 공헌의 가장 긴 상승 수의 서브 시퀀스의 수를 찾을 필요가 있지만, 이것은 좋지 않다 수량 통계; 간주 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; 
}

 

추천

출처blog.csdn.net/qq_41157137/article/details/92787559