题解 P2717 寒假作业

Solution

先把 \(a_i\) 都减 \(k\),那么问题就变为求和 \(\ge0\) 的子串个数。

然后再把减去了 \(k\)\(\{a\}\) 做前缀和,记为 \(\{s\}\),问题又变为求满足 \(s_i-s_j\ge0(i>j)\)\((i,j)\) 的个数也就是 \(\{s\}\)顺序对个数,用树状数组或归并排序求就好了 。

因为我用的是树状数组且没离散化,复杂度为 \(\mathcal O(n\log10^9)\)

Code

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define ll long long
using namespace std;
using namespace __gnu_pbds;
const int N=1e5+5;
int n,mins=1e9,k,s[N];
ll ans;
gp_hash_table<int,int>c;//pbds的哈希表
inline void add(int x){for(;x<=1e9;x+=x&-x)c[x]++;}
inline ll ask(int x){ll res=0;for(;x;x-=x&-x)res+=c[x];return res;}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",s+i),mins=min(mins,s[i]+=s[i-1]-k),ans+=(s[i]>=0);//统计j=0的情况
    for(int i=1;i<=n;i++){
        s[i]-=mins-1;//使每个Si都>0
        ans+=ask(s[i]);
        add(s[i]);
    }printf("%lld\n",ans);//答案可能爆int
    return 0;
}

注意答案可能爆 \(\text{int}\),也证明作业不是 \(\text{int}\) 能存下的

posted @ 2021-08-22 18:56  ADay526  阅读(199)  评论(0)    收藏  举报