【基础练习】【归并逆序对】codevs3324 新斯诺克题解
2015-10-24 08:32
239 查看
题目描述 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
这道题目要求我们求出有多少种连续的数,其平均数大于m
换句话说,就是有多少种连续的数,和大于m*i
那么我们可以用一个前缀和数组做 从i到j的和可以表示为s[j]-s[i-1]
那么我们求的是:对于任意i和j,有多少能满足i<j&&s[j]-s[i]>m(j-i)
这个式子实质求的是顺序对,其实只不过是统计的地方变了一下而已,但脑子容易晕
如果我们不愿意求顺序对,也可以更简单的求逆序对 原式可化简为:i<j && m*i-s[i]>m*j-s[j]
这样 我们令a[i]=m*i-s[i] 就可以直接做逆序对了
标准代码最好还是这一种,安全稳定
——峡束苍江对起,过危楼,欲飞还敛。
斯诺克又称英式台球,是一种流行的台球运动。在球桌上,台面四角以及两长边中心位置各有一个球洞,使用的球分别为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
这道题目要求我们求出有多少种连续的数,其平均数大于m
换句话说,就是有多少种连续的数,和大于m*i
那么我们可以用一个前缀和数组做 从i到j的和可以表示为s[j]-s[i-1]
那么我们求的是:对于任意i和j,有多少能满足i<j&&s[j]-s[i]>m(j-i)
这个式子实质求的是顺序对,其实只不过是统计的地方变了一下而已,但脑子容易晕
如果我们不愿意求顺序对,也可以更简单的求逆序对 原式可化简为:i<j && m*i-s[i]>m*j-s[j]
这样 我们令a[i]=m*i-s[i] 就可以直接做逆序对了
标准代码最好还是这一种,安全稳定
//codevs3324 ÐÂ˹ŵ¿Ë ¹é²¢ÄæÐò¶Ô //copyright by ametake #include #include #include #define ll long long using namespace std; const ll maxn=100000+10; ll a[maxn],b[maxn],s[maxn]; ll n,m; ll tot=0; void msort(ll l,ll r) { ll mid = l + r >> 1; if (l0 { msort(l,mid); msort(mid+1,r); } ll i=l,k=l,j=mid+1; while (i<=mid&&j<=r) { if (a[i]<=a[j]) b[k++]=a[i++]; else { tot+=mid-i+1; b[k++]=a[j++]; } } while (i<=mid) b[k++]=a[i++]; while (j<=r) b[k++]=a[j++]; for (ll i=l;i<=r;i++) a[i]=b[i]; } int main() { scanf("%d%d",&n,&m); a[0]=0; s[0]=0; for (ll i=1;i<=n;i++) { scanf("%d",&a[i]); s[i]=s[i-1]+a[i]; a[i]=m*i-s[i]; } msort(0,n); //for (ll i=0;i<=n;i++) prllf("%lld ",b[i]); printf("%lld\n",tot); return 0; } /*°ÂÉñ¹é²¢ÄæÐò¶ÔÄ£°å ll a , tmp ; void msort(ll l, ll r) { ll mid = l + r >> 1; if(l < r) { msort(l, mid); msort(mid + 1, r); } ll i = l, j = mid+1, k = l; while(i <= mid && j <= r) { if(a[i] <= a[j]) tmp[k++] = a[i++]; else { ans += mid - i + 1; tmp[k++] = a[j++]; } } while(i <= mid) tmp[k++] = a[i++]; while(j <= r) tmp[k++] = a[j++]; for(i = l; i <= r; ++i) a[i] = tmp[i]; } */
——峡束苍江对起,过危楼,欲飞还敛。
相关文章推荐
- C++实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等
- 计算机科学中32个常用的基础算法
- Java实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等
- Java排序算法总结之归并排序
- C++归并排序算法实例
- Javascript排序算法之合并排序(归并排序)的2个例子
- 归并排序的递归实现与非递归实现代码
- java二路归并排序示例分享
- java实现归并排序算法
- 归并排序的实现代码与思路
- 逆序对
- leetcode 虐我篇之(二) Two Sum
- In-place Merge Sort 原地并归排序
- 使用Java完成《算法导论》习题2.3-2
- 插入排序移动次数
- 归并排序 with Python
- 归并排序-逆序对的求解
- 排序算法的复杂度和稳定性
- java算法-快速排序
- java算法-二分查找法