[abc] E - LEQ 树状数组+组合计数

前言

真简单,树状数组真简单,数论真简单 (我在口胡)

传送门 : https://atcoder.jp/contests/abc221/tasks/abc221_e

补题借鉴 : https://zhuanlan.zhihu.com/p/416410911

思路

题目需要求的是 满足 所有组数

A 1 ′ ≤ A k ′ A_{1}^{\prime} \leq A_{k}^{\prime} A1Ak

因此不难想象 如果我们排序之后 那么我们只需要枚举k

对于每一个k我们都求出所有可能 即 2 k 2^{k} 2k (二进制枚举中有用到)

C ( N , 0 ) + C ( N , 1 ) + C ( N , 2 ) + … + C ( N , N ) = 2 n C(N, 0)+C(N, 1)+C(N, 2)+\ldots+C(N, N)=2^{n} C(N,0)+C(N,1)+C(N,2)++C(N,N)=2n

因此 这题的 最终需要求的就是 : ∑ 1 ≤ i < j ≤ n 2 j − i − 1 [ a i ≤ a j ] \sum_{1 \leq i<j \leq n} 2^{j-i-1}\left[a_{i} \leq a_{j}\right] 1i<jn2ji1[aiaj]

  1. 对于我们在枚举 i 的时候 我们可以将公式拆分 ∑ i ≤ j ≤ n 2 j [ a i ≤ a j ] \sum_{i \leq j \leq n} 2^{j}\left[a_{i} \leq a_{j}\right] ijn2j[aiaj]
    然后我们在乘上 2 − i − 1 2^{-i-1} 2i1 又因为这题范围 2e5 因此我们需要在O(logn)的范围求出求和公式的值

  2. 我们可以用树状数组来处理 ∑ 2 j \sum 2^{j} 2j

  3. 最后我们只需要用 逆元 处理一下 乘上的 2 1 + i 2^{1+i} 21+i

优化 :

  1. 为了使 数组元素不超过n 因此我们需要对a数组进行离散化
  2. cc_hasptable 竟然比 hashmap还快一倍
  3. 这个树状数组这样写也太棒了吧

CODE

#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
using ll = long long;
const int N = 3e5+10;
const int mod  = 998244353;

ll ans;

ll a[N],b[N];

struct node
{
    int n;
    ll T[N];

    ll lowbit(ll x)
    {
        return x&(-x);
    }

    void modify(int pos,ll x)
    {
        for(int i=pos;i<=n;i+=lowbit(i))
            T[i]+=x;
    }

    ll ask(int pos)
    {
        ll ans  = 0 ;
        for(int i = pos;i>=1;i-=lowbit(i))
        ans+=T[i];
        return ans;
    }

    ll query(int l,int r)
    {
        return (ask(r) - ask(l-1) + mod)%mod;
    }
}T;
ll qmi(ll a,ll b)
{
    ll res = 1;
    a%=mod;

    while(b>0){
        if(b&1)
            res = res*a%mod;
        a = a*a % mod;
        b>>=1;
    }
    return res;
}

/// 求b*x == 1 mod p
/// 费马小定理 求出  x == b^(p-2)
ll inv(ll x)
{
    return qmi(x,mod - 2);
}

void solve()
{
    int n;
    cin>>n;
    T.n = n;

    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i] = a[i];
    }

    /*离散化*/
    sort(b+1,b+1+n);
    cc_hash_table<int,int> rk;
    for(int i=1;i<=n;i++)
    rk[b[i]] = i ;


    for(int i=1;i<=n;i++)
    T.modify(rk[a[i]],qmi(2,i));

    for(int i=1;i<=n;i++)
    {
        T.modify(rk[a[i]], - qmi(2,i)+mod);

        ans += inv(qmi(2,i+1)) * T.query(rk[a[i]],n);

        ans%=mod;
    }
    cout<<ans%mod<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    solve();
    return 0;
}

//1 2 3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值