1. 程式人生 > >codevs 3324 新斯諾克

codevs 3324 新斯諾克

均值 條件 ble 認識 std amp 之前 滿足 temp

3324 新斯諾克

時間限制: 1 s 空間限制: 64000 KB 題目等級 : 白銀 Silver 題目描述 Description

斯諾克又稱英式臺球,是一種流行的臺球運動。在球桌上,臺面四角以及兩長邊中心位置各有一個球洞,使用的球分別為1 個白球,15 個紅球和6 個彩球(黃、綠、棕、藍、粉紅、黑)共22個球。

擊球順序為一個紅球、一個彩球直到紅球全部落袋,然後以黃、綠、棕、藍、粉紅、黑的順序逐個擊球,最後以得分高者為勝。斯諾克的魅力還在於可以打防守球,可以制造一些障礙球使對方無法擊打目標球而被扣分。正是因為這樣,斯諾克是一項充滿神奇的運動。

現在考慮這樣一種新斯諾克,設母球(母球即是白球,用於擊打其他球)的標號為M,臺面上有N 個紅球排成一排,每一個紅球都有一個標號,他們的標號代表了他們的分數。

現在用母球擊打這些紅球,一桿擊打,如果母球接觸到紅球,就稱為“K 到紅球”。我們假設,一次可以擊打任意多相鄰連續的紅球,也可以只擊打一個球。並且紅球既不會落袋,也不會相互發生碰撞,而只是停留在原處。每次擊打時候,要想“K 到紅球”,至少要擊打一個紅球,如果想一次擊打多個紅球,那麽擊打的紅球必須是依次連續排列的。如果一次“K 到紅球”所有紅球的標號之和的平均數大於母球的標號M,就獲得了一個“連擊”。

現在請你計算總共能有多少種“連擊”方案。

註意:如果當前有標號為1、2、3 的三種紅球,母球標號為0,有如下6 種獲得“連擊”方案:( 1)、( 2)、( 3)、( 1,2)、( 2,3)、( 1,2,3)

輸入描述 Input Description

共有兩行。

第一行是N,M (N<=100000,M<=10000) ,N 表示臺面上一共有N 個紅球,M 表示母球的標號。

第二行是N 個正整數,依次表示臺面上N 個紅球的標號,所有標號均不超過10000。

輸出描述 Output Description

只有一個數,為“連擊”的方案總數。

樣例輸入 Sample Input

4 3

3 7 2 4

樣例輸出 Sample Output

7

數據範圍及提示 Data Size & Hint

請看上面。

【題目大意】

滿足連續的區間的平均值大於k的區間有多少個。

【思路】

歸並排序

【code1】

爸爸一上來就打了暴力啊。10分暴力ORZ

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,ans;
int sum[100005],a[100005];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=0;i<=n;i++)
    for(int j=i+1;j<=n;j++)
    {
        if((sum[j]-sum[i])/(j-i)>m)ans++;
    }
    printf("%d\n",ans);
    return 0;
}

【code2】

這個題真是個好題...我做過的最巧的一個題(不要問我以前做的什麽題)。

做這個題時我深刻的認識到(嚴肅臉)做題不能光想啊 還要手動推一推 \Qwq/

設滿足條件的區間為[i+1,j].

那麽 (sum[j]-sum[i])/(j-i) > m

即(乘過去)

sum[j]-sum[i]>m*j-m*i;

sum[j]-m*j>sum[i]-m*i;

設A[i]=sum[i]-m*i;

所以 A[j]>A[i] (j>i)

我們算時 把A[i]=m*i-sum[i] 也就是之前設的A[i]的相反數 為了下面好做 我們重新定義。

式子就成了

A[J]<A[i] (j>i)

然後就愉快的歸並排序啦。

註意:逆序對個數開long long 前綴也要開long long 。

因為前面的是[i+1,j] 歸並排序要從(0,n)

左端點=0時就是連擊全部的情況。

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,k,x;
long long tot;
long long a[100005],temp[100005];
void merge_sort(int left,int right)
{
    if(left==right)return;
    int mid=(left+right)/2;
    merge_sort(left,mid);merge_sort(mid+1,right);
    int p=left,i=left,j=mid+1;
    while(i<=mid&&j<=right)
    {
        if(a[i]>a[j])
        {
            tot+=mid-i+1;
            temp[p++]=a[j++];
        }
        else
        temp[p++]=a[i++];
    }
    while(i<=mid)temp[p++]=a[i++];
    while(j<=right)temp[p++]=a[j++];
    for(int i=left;i<=right;i++)
    a[i]=temp[i];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        k+=x;a[i]=m*i-k;
    }
    merge_sort(0,n);
    printf("%lld\n",tot);
    return 0;
}

codevs 3324 新斯諾克