【复赛模拟试题】新斯诺克 逆序对

来源:互联网 发布:淘宝超级快车好用吗 编辑:程序博客网 时间:2024/04/27 14:59

【问题描述】

  考虑这样一种新斯诺克,设母球(母球即是白球,用于击打其他球)的标号为m,台面上有 N 个红球排成一排,每一个红球都有一个标号,他们的标号代表了他们的分数。现在用母球击打这些红球,一杆击打,如果母球接触到红球,就称为“K到红球”。我们假设,一次可以击打任意多相邻连续的红球,也可以只击打一个球。并且红球既不会落袋,也不会相互发生碰撞,而只是停留在原处。每次击打时候,要想“K到红球”,至少要击打一个红球,如果想一次击打多个红球,那么击打的红球必须是依次连续排列的。如果一次 “K到红球”所有红球的标号之和的平均数大于母球的标号m,就获得了一个 “连击”。现在给定你一个局面,请你计算总共能有多少种“连击”方案。
  例如当前有4个红球排成一排,它们的标号依次为3, 7, 2, 4,母球标号为m=3, 则有如下 7 种“连击”方案: (7)、(4)、(3,7)、(7,2)、(3,7,2)、(7,4,2)、(3,7,2,4)。因为(3)和(2,4)中红球标号的平均值不大于3,所以它们不是合法的“连击”方案。

【输入格式】

  输入共有两行,第一行是 n m,n 表示台面上一共有 n 个红球,m 表示母球的标号。第二行是 n 个正整数,依次表示台面上 n 个红球的标号。所有标号均不超过2*10^9。

【输出格式】

  输出只有一个数,为“连击”的方案总数。

【输入样例】

4 3
3 7 2 4

【输出样例】

7

【数据范围】

30%的数据满足:n≤1000
100%的数据满足: n<=100000, m<=10^9

——————————————————————————————————————————————

暴力没问题,转化一下就发现可以把上面的连击描述成一个新的数组(A[i]-M)的前缀和数组的逆序对。
时间复杂度O(nlogn)

给出各种解法的代码(暴力、归并排序、树状数组)。注意一下求逆序对的时候前缀和里面一定要多放一个0进去,因为这个前缀和只要大于0就是合法的。

AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>using namespace std;typedef long long LL;const int maxn=100005;int N,M,num[maxn];LL ans,sum[maxn],tmp[maxn];LL A[maxn],B[maxn];int C[maxn],MAX;void _scanf(int &x){    x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void data_in(){    _scanf(N);_scanf(M);    for(int i=1;i<=N;i++) _scanf(num[i]);}void work30()//对于每个球,向右枚举以这个球为起点的连续区间。 {    for(int i=1;i<=N;i++)    {        LL now=0;        for(int j=i;j<=N;j++)        {            now+=num[j];            if((LL)M*(j-i+1)<now) ans++;        }    }    cout<<ans<<endl;}LL msort(int L,int R,LL *a)//从大到小排序 {    if(R-L<=1) return 0;    int m=L+R>>1;    LL t1=msort(L,m,a);    LL t2=msort(m,R,a);    LL t3=0;    int i=L,j=m,cnt=L;    while(i<m&&j<R)    {        if(a[i]<a[j]) tmp[cnt++]=a[j++],t3+=m-i;        else tmp[cnt++]=a[i++];    }    while(i<m) tmp[cnt++]=a[i++];    while(j<R) tmp[cnt++]=a[j++];    for(int k=L;k<R;k++) a[k]=tmp[k];    return t1+t2+t3;}void work100_1(){    for(int i=1;i<=N;i++)        sum[i]=sum[i-1]+num[i]-M;    ans=msort(0,N+1,sum);    cout<<ans<<endl;}void LSH(LL *a){    memcpy(B,sum,sizeof(B));    sort(B,B+N+1);    int cnt=unique(B,B+N+1)-B;    for(int i=0;i<=N;i++)    {        A[i]=lower_bound(B,B+cnt+1,sum[i])-B+1;        if(A[i]>MAX) MAX=A[i];    }}int lowbit(int i) { return i&(-i); }int add(int i){    LL re=0;    while(i>0) re+=C[i],i-=lowbit(i);    return re;}void update(int i,int d){    while(i<=MAX) C[i]+=d,i+=lowbit(i);}void work100_2(){    for(int i=1;i<=N;i++)        sum[i]=sum[i-1]+num[i]-M;    LSH(sum);    for(int i=0;i<=N;i++)    {        ans+=add(A[i]-1);        update(A[i],1);    }    cout<<ans<<endl;}int main(){    freopen("snooker.in","r",stdin);    freopen("snooker.out","w",stdout);    data_in();//  work30();    work100_1();//  work100_2();    return 0;}
原创粉丝点击