球——数学分析,模型构建

我们假设, 一次可以击打任意多相邻连续的红球,也可以只击打一个球。 并且红球既不会落袋,也不会相

互发生碰撞,而只是停留在原处。每次击打时候,要想“K到红球”,至少要击打一个红球,如果想一次击打

多个红球,那么击打 的红球必须是依次连续排列的。 如果一次“K到红球”所有红球的标号之和的平均数大于

母球的标号 \(M\),就获得了一 个“连击”。

现在请你帮帮 hs_black 计算总共能有多少种“连击”方案。注意:如果当前有标号为 \(1,2,3\) 的三种红球,母球标号为 \(0\),有如下 \(6\) 种获得“连击”方 案:\((1),(2),(3),(1,2),(2,3),(1,2,3)\)

输入格式

输入共有两行,第一行是\(N\)\(M\) (\(N⩽100000,M⩽10000\)) ,NN 表示台面 上一共有 \(N\) 个红球,\(M\) 表示

母球的标 号。 第二行是 \(N\) 个正整数,依次表示台面上 \(N\) 个红球的标号,所有标号均不超过 \(10000\)

输出格式

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

思路

先说一下暴力,维护一个前缀和,\(n^2\)的时间复杂度扫一遍就行,

说正解,学会手玩式子还是挺重要的

我们要求的就是满足\(\dfrac{sum\left[ j\right] -sum\left[ i\right] }{j-i} >m\)的区间的个数,这里规定\(j>i\)

我们变形一下便会得到

\(sum\left[ j\right] -sum\left[ i\right] >mj-mi(j>i)\)

\(sum\left[ j\right] -mj >sum\left[ i\right] -mi(j>i)\)

不妨把\(sum[j]-mj\)\(sum[i]-mi\)分别看成单独的两项,即\(v[j],v[i]\)

问题就简化成了\(v[j]>v[i](j>i)\)

看到这个我们还是没法用我们已知的算法进行求解,我们看到这个形式不难会想到逆序对

只要我们再取一次反,不就变成了\(v[j]<v[i](j>i)\),也就是求逆序对的问题吗

归并求或者树状数组进行求解都是可以的

但是这个注意有个小细节,就是如果单独的一个数是大于\(m\)的,那么它也是满足条件的,

为了不漏掉这种情况,我们在数的最开始加一个值为0的数

那会不会对其他情况产生影响呢,答案是不会的,因为我们的\(v[]\)早已经处理好了

代码

就是归并排序求逆序对的写法

#include<bits/stdc++.h>
using namespace std;
const int N=200000;
int sum[N];
int n,m;
int a[N];
template <typename T> inline void read(T &x) {
	x = 0; char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
}
long long res;
int q[N],tmp[N];
long long merge_sort(int q[],int l,int r)
{
    if(l>=r)return 0;
    int mid=(l+r)/2;
    res=merge_sort(q,l,mid)+merge_sort(q,mid+1,r);
    int k=0;
    int i=l;
    int j=mid+1;
    while(i<=mid&&j<=r)
    {
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else {
            res+=(mid-i+1);
            tmp[k++]=q[j++];
        }
    }
    while(i<=mid)tmp[k++]=q[i++];
    while(j<=r) tmp[k++]=q[j++];
    for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
    return res;
}
int main()
{
	read(n);
	read(m);
	for(int i=1;i<=n;i++)
	{
		int x;
		read(x);
		sum[i]=sum[i-1]+x;
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i]-i*m;
		sum[i]=-sum[i];
	}
    //产生新的sum数组 产生方式就是sum[i]=-(sum[i]-mi)
	merge_sort(sum,0,n);
	cout<<res<<endl;
	return 0;
}
posted @ 2020-11-12 21:48  邦的轩辕  阅读(57)  评论(0编辑  收藏  举报