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


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

    互发生碰撞,而只是停留在原处。每次击打时候,要想“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{sumleft[ j ight] -sumleft[ i ight] }{j-i} >m)的区间的个数,这里规定(j>i)

    我们变形一下便会得到

    (sumleft[ j ight] -sumleft[ i ight] >mj-mi(j>i))

    (sumleft[ j ight] -mj >sumleft[ i ight] -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;
    }
    
  • 相关阅读:
    数据库中生成UUID的方式
    db2如果修改主机名之后
    linux修改主机名
    db2动态查看备份进度
    oracle-DG
    linux环境变量和对应文件的生效顺序
    数据泵与传统exp/imp对比
    oracle之ogg部署(RAC到单机)
    oracle之ogg部署(单机到单机)
    达梦 (实时主备+数据守护)测试
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/13966458.html
Copyright © 2020-2023  润新知