题解 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}\) 能存下的

浙公网安备 33010602011771号