题解分享:反恐精英Counter Strike

题目来源:杭电oj2443

题目:

Anti-terrorism is becoming more and more serious nowadays. The country now has n soldiers,and every solider has a score. We want to choose some soldiers to fulfill an urgent task. The soldiers chosen must be adjacent to each other in order to make sure that they can cooperate well. And all the soldiers chosen must have an average score greater than a. Now, please calculate how many ways can the chief of staff choose the soldiers.

翻译:如今,反恐形势变得越来越严峻。国家目前有n名士兵,且每名士兵都有一个分数。我们想要挑选一些士兵去执行一项紧急任务。为了确保他们能够良好地协同作战,被挑选的士兵必须是相邻的。并且所有被挑选的士兵的平均分数必须大于a。现在,请计算参谋长有多少种挑选士兵的方法。

输入格式 The first line consists of a single integer t, indicating number of test cases. For each test case, the first line gives n, the number of soldiers, and a, the minimum possible average score(n<=100000,a<=10000). The second line gives n integers, corresponding to the soldiers' scores in order. All the scores are no greater than 10000.

翻译:第一行包含一个整数t,表示测试用例的数量。对于每个测试用例,第一行给出n(士兵的数量)和a(可能的最低平均分数,n≤100000,a≤10000)。第二行给出n个整数,依次对应着士兵们的分数。所有的分数都不大于10000。

输出格式 An integer n, number of ways to choose the soldiers.一个整数n,即挑选士兵的方法数。

输入样例 2

                5 3

                1 3 7 2 4

                1 1000

                9999

输出样例 10 1

分析:本题大概意思是需要选相邻的士兵而且这些士兵的分数需要平均值大于a,输出最后满足条件选择士兵的方案数量。第一行给出t说明要用多case样例,再来观察一下,样例的数据量大小,是10000,如果采用O(n²)级别必然导致超时,所以该题只能采用O(n)级别的运算量。

假设每一个士兵的分数依次为s1,s2,s3,……

列出算式:如果满足题意,该方案必然形如(s1+s2+s3)/3>a,即s1+s2+s3>3a,为了方便表示,我们可以把a分别和s1进行相减处理,假设y1=s1-a,y2=s2-a,y3=s3-a,得到y1+y2+y3>0,因此对于该题目我们第一步可以先将所有数据减去要求的a值,最后判断时只需要满足相加为正值即可满足

(该操作在算法中常用,称为标准化,即把已知和标准值作差,最后和标准比较时只要考虑正负)

由上面我们可以知道问题转化为每一个部分的和为正值的数量

由于我们需要计算出所有形如s1+s2的值,我们可以考虑使用动态思维,即前一次计算出的值后面可以使用,这里,每一个部分的和我们需要关注的是最后一个累加的总和与初始位置前一个的累加的总和(比如说我们要计算出第三个数到第六个数的和,我们可以用1到6个数的总和减去1到2个数的总和),所以这里我们要计算出每一个部分的累加和,我们进行第二步处理,定义一个数组,依次记录从第一个数加到第n个数的和。

(该操作在算法也常用,称为部分和,与之相似的还有前缀和等等)

由上面我们可以再把问题转化为第n个部分和减去第m-1个部分和的正值的关系

观察可知,假设数组k为部分和,那么k[n]-k[m-1]>0和n>m-1,这两个条件我们可以得到它是一个正序对,至此该题的思路已经确定

1、标准化:将每一个数减去a得到标准值

2、部分和:定义一个数组,计算出从第1个到第n个的累加和

3、正序对:利用归并排序思维,计算出这个数组有多少个正序对

4、提升:为了不出现m-1这种,可以把k[0]=0,然后k[n]=s[n]+k[n-1],然后计算出从0到n的正序对,这样就可以避免m-1的复杂讨论。

代码实现:

#include<iostream>
using namespace std;
int res=0;//将结果定义为全局变量,记得每次都要初始为0
void Mergesort(int l,int r,int arr[])//计算正序对
{
    if(l>=r) return ;
    int *temp=new int[r-l+1];
    int mid=(l+r)/2;
    Mergesort(l,mid,arr);
    Mergesort(mid+1,r,arr);
    int k=0,i=l,j=mid+1;
    while(i<=mid&&j<=r)
    {
        if(arr[i]<arr[j])
        {
            temp[k++]=arr[i++];
            res+=r-j+1;
        }
        else
            temp[k++]=arr[j++];
    }
    while(i<=mid)
        temp[k++]=arr[i++];
    while(j<=r)
        temp[k++]=arr[j++];
    for(i=l,k=0;i<=r;i++,k++)
        arr[i]=temp[k];
}
int main()

{
    int t;
    cin>>t;
    while(t--)
    {
        int n,a;
        cin>>n>>a;
        res=0;
        int *k=new int[n+1];
        k[0]=0;
        for(int i=1;i<=n;i++)
        {
            int j;//读进士兵的分数
            cin>>j;
            j-=a;//计算出标准值
            k[i]=k[i-1]+j;//计算出部分和
        }
        Mergesort(0,n,k);
        cout<<res<<" ";
    }
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值