poj1990
2015-11-09 16:15
316 查看
题目意思就是有m头牛,每头牛有两个值,v和x,两两之间有一个值,设v分别为v1,v2,x为x1,x2,则它们之间的值为abs(x1-x2) * Max(v1,v2),求所有m*(m-1)/2对牛之间值的总和。
暴力的话很好理解了,但是这里的m数据范围最大为20000,n^2的效率是不可取的。所以这里我们引入树状数组。这道题目我们得用两个两个树状数组,一个叫做num[x],可以计算小于坐标x的坐标有几个,另外一个叫做sum[x],可以将计算小于坐标x的坐标的总和。除此之外,我们还用一个变量total,来保存前面计算机过的坐标总和。
计算方法是这样的,我们拿例子来说,
4
3 1
2 5
2 6
4 3
首先,我们得将它们按照v从小到大排序,这样子每到一头牛,那么只要计算它与之前的坐标差,然后乘上它的v即可。排序后得到:
2 2 3 4
5 6 1 3
我们先计算5这个,发现它的前面没有坐标,那么就没有好计算的,total+=5,更新num和sum。[total=5]
然后计算6,发现它前面有个坐标5,它们之间的坐标差为6*1-5=1,后面暂时没有坐标,ans = ans+1*2,total+=6,更新num和sum。[total=11]
接着计算1,发现它前面没有坐标,但是此时i=3,说明它的后面有3-0-1个坐标,坐标差为 total-1*2 = 9, ans = ans + 9*3,total += 1,更新num和sum。[total=12].
最后计算3,发现它前面有个坐标1,它们之间坐标差为3*1-1=2,后面有4-1-1=2个坐标,坐标差为 total-1-2*3 = 11-6=5,所以坐标差总共为2+5=7,
ans = ans + 7*4 = ans+28,total += 3,更新num和sum。[total = 15]
最后的ans得出就是57。
更具体的详见代码:
暴力的话很好理解了,但是这里的m数据范围最大为20000,n^2的效率是不可取的。所以这里我们引入树状数组。这道题目我们得用两个两个树状数组,一个叫做num[x],可以计算小于坐标x的坐标有几个,另外一个叫做sum[x],可以将计算小于坐标x的坐标的总和。除此之外,我们还用一个变量total,来保存前面计算机过的坐标总和。
计算方法是这样的,我们拿例子来说,
4
3 1
2 5
2 6
4 3
首先,我们得将它们按照v从小到大排序,这样子每到一头牛,那么只要计算它与之前的坐标差,然后乘上它的v即可。排序后得到:
2 2 3 4
5 6 1 3
我们先计算5这个,发现它的前面没有坐标,那么就没有好计算的,total+=5,更新num和sum。[total=5]
然后计算6,发现它前面有个坐标5,它们之间的坐标差为6*1-5=1,后面暂时没有坐标,ans = ans+1*2,total+=6,更新num和sum。[total=11]
接着计算1,发现它前面没有坐标,但是此时i=3,说明它的后面有3-0-1个坐标,坐标差为 total-1*2 = 9, ans = ans + 9*3,total += 1,更新num和sum。[total=12].
最后计算3,发现它前面有个坐标1,它们之间坐标差为3*1-1=2,后面有4-1-1=2个坐标,坐标差为 total-1-2*3 = 11-6=5,所以坐标差总共为2+5=7,
ans = ans + 7*4 = ans+28,total += 3,更新num和sum。[total = 15]
最后的ans得出就是57。
更具体的详见代码:
#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<iomanip> #include<vector> #include<time.h> #include<queue> #include<stack> #include<iterator> #include<math.h> #include<stdlib.h> #include<limits.h> #include<map> #include<set> #include<bitset> //#define ONLINE_JUDGE #define eps 1e-8 #define INF 0x7fffffff #define FOR(i,a) for((i)=0;i<(a);(i)++) #define MEM(a) (memset((a),0,sizeof(a))) #define sfs(a) scanf("%s",a) #define sf(a) scanf("%d",&a) #define sfI(a) scanf("%I64d",&a) #define pf(a) printf("%d\n",a) #define pfI(a) printf("%I64d\n",a) #define pfs(a) printf("%s\n",a) #define sfd(a,b) scanf("%d%d",&a,&b) #define sft(a,b,num) scanf("%d%d%d",&a,&b,&num) #define for1(i,a,b) for(int i=(a);i<b;i++) #define for2(i,a,b) for(int i=(a);i<=b;i++) #define for3(i,a,b)for(int i=(b);i>=a;i--) #define MEM1(a) memset(a,0,sizeof(a)) #define MEM2(a) memset(a,-1,sizeof(a)) #define ll long long const double PI=acos(-1.0); template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} template<class T> inline T Min(T a,T b){return a<b?a:b;} template<class T> inline T Max(T a,T b){return a>b?a:b;} using namespace std; #define M 20010 ll num[M]; //num[x]用来存储在[1,x]之间存储的坐标的个数 ll sum[M]; //sum[x]用来存储在[1,x]之间存储的坐标的和 int n; int lowbit(int x){ return x&(-x); } struct Cow{ int val,x; bool operator <(const Cow &a) const{ return val<a.val; } }a[M]; ll getSum(ll *arr,int i){ //树状数组向下求和 ll sum=0; while(i>0){ sum += arr[i]; i -= lowbit(i); } return sum; } void upDate(ll *arr,int i,int val){ //树状数组向上更新 while(i<=n){ arr[i] += (ll)val; i += lowbit(i); } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif int m; while(sf(m)!=EOF){ memset(num,0,sizeof num); memset(sum,0,sizeof sum); n = -1; for(int i=1;i<=m;i++){ scanf("%d%d",&a[i].val,&a[i].x); n = Max(n,a[i].x); //n为最大的坐标,也就是树状数组的右边界 } sort(a+1,a+m+1); //依volume从小到大排序 ll total=0; //记录前i-1头牛所有的volume值的和 ll ans=0; for(int i=1;i<=m;i++){ ll nm = getSum(num,a[i].x); //计算小于a[i].x的坐标的个数 ll sm = getSum(sum,a[i].x); //计算小于a[i].x的坐标的和 ll small = nm*a[i].x-sm; //计算小于a[i].x的坐标与a[i].x之间的坐标差 ll big = total-sm-(i-1-nm)*a[i].x; //计算大于a[i].x的坐标与a[i].x之间的坐标差, //其中,total-sm是大于a[i].x的vol和,(i-1-nm)是大于a[i].x的坐标的个数 ll val = (small+big)*a[i].val; //计算所有小于等于a[i].val的坐标差*a[i].val //pfI(val); ans += val; total += a[i].x; //更新total upDate(num,a[i].x,1); //更新坐标个数 upDate(sum,a[i].x,a[i].x); //更新坐标的和 } pfI(ans); } return 0; }
相关文章推荐
- 分页查询-sql优化
- iOS多线程的几种创建方式
- 王者调整期选股技术之喇叭花开
- XmlHttpRequest
- centos平台openstack spice配置
- 第十一周项目一-二叉树算法验证(层次便利算法的验证)
- 数据结构实践—— 二叉树遍历的递归算法
- 一:Hadoop简介
- Integer和String底层原理
- java知识点总结
- 第十周 项目1--二叉树算法库
- URAL 1243 Divorce of the Seven Dwarfs
- C++笔记(一)
- Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分
- 第十一周上机实践—项目1(1)—层次遍历算法的验证
- Android应用内跨进程通信AIDL实例与源码
- Javascript垃圾回收机制(学习笔记)
- github air项目中遇到的几个问题及解决(nodejs居多)
- 字符串String
- 第十一周项目一~~层次遍历的算法