codevs 3324 新斯諾克
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)
共有兩行。
第一行是N,M (N<=100000,M<=10000) ,N 表示臺面上一共有N 個紅球,M 表示母球的標號。
第二行是N 個正整數,依次表示臺面上N 個紅球的標號,所有標號均不超過10000。
輸出描述 Output Description只有一個數,為“連擊”的方案總數。
樣例輸入 Sample Input4 3
3 7 2 4
樣例輸出 Sample Output7
數據範圍及提示 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 新斯諾克