1. 程式人生 > >Codevs3324 新斯諾克

Codevs3324 新斯諾克

  • 題目大意:給定一個具有n個數的數列和一個數m,求有多少個連續子序列的和的平均數大於m。

  • 思路:平均數是不用管的,數列中每個數直接減去即可,這樣條件轉化為連續子序列的和大於0。再由此聯想到陣列的字首和,則某一段序列和a[i]+…+a[j]=s[j]-s[i-1],符合條件的話,則有s[j]-s[i-1]>0,即s[j]>s[i-1],由此轉化為求逆序對數。

  • 程式碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100005
; long long n,m,s[maxn],res=0,c[maxn]; void init() { memset(s,0,sizeof(s)); scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) { int tmp; scanf("%d",&tmp); s[i]=s[i-1]+tmp-m; } } void msort(int l,int r) { if (l==r) { c[l]=s[l]; return
; } int mid=(l+r)/2; msort(l,mid); msort(mid+1,r); int i=l,j=mid+1,k=l; while (i<=mid && j<=r) { if (s[i]>=s[j]) { c[k]=s[j]; res+=(mid-i+1); j++; k++; } else
{ c[k]=s[i]; i++; k++; } } while (i<=mid) { c[k]=s[i]; i++; k++; } while (j<=r) { c[k]=s[j]; j++; k++; } for (int i=l;i<=r;++i) s[i]=c[i]; } int main() { init(); msort(0,n); n++; long long ans=n*(n-1)/2; printf("%lld",ans-res); return 0; }