牛客提高D3t2 点与面

分析

对于每一个点只要维护它前面/后面的一小一大组合的数量

对于这个可以维护两个树状数组

然后从前往后/从后往前分别扫一遍相乘即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
const int mod = 998244353;
#define add(x,y) x=(x+y)%mod
#define del(x,y) (x-y+mod)%mod
inline int lb(int x){return x&(-x);}
int a[1000100],b[1000100],sum1[100100],sum2[100100],h[100100],n,m;
inline void add_a(int x,int k){while(x<=m)add(a[x],k),x+=lb(x);return;}
inline void add_b(int x,int k){while(x<=m)add(b[x],k),x+=lb(x);return;}
inline int q_a(int x){int res=0;while(x)add(res,a[x]),x-=lb(x);return res;}
inline int q_b(int x){int res=0;while(x)add(res,b[x]),x-=lb(x);return res;}
signed main(){
    int i,j,k;
    scanf("%lld",&n);
    for(i=1;i<=n;i++){
      scanf("%lld",&h[i]);
      m=max(m,h[i]);
    }
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(i=1;i<=n;i++){
      add_a(h[i],1);
      add_b(h[i],del(q_a(m),q_a(h[i])));
      sum1[i]=q_b(h[i]-1);
    }
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(i=n;i>0;i--){
      add_a(h[i],1);
      add_b(h[i],del(q_a(m),q_a(h[i])));
      sum2[i]=q_b(h[i]-1);
    }
    int ans=0;
    for(i=1;i<=n;i++)
      ans=(ans+1ll*sum1[i]*sum2[i]%mod)%mod;
    cout<<ans<<"\n";
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yzxverygood/p/11405752.html