• luoguP5094 [USACO04OPEN]MooFest 狂欢节


    get 到的

    这种需要求 含 max 的式子枚举最大值的方法非常普遍。

    类似的,还有含 min , gcd 的式子,枚举他们也很普遍

    主要难点

    我们首先想到,先按 v 从小到大排序,因为这样既可以简化题意(即题意:每次都只需求第i头牛 之前的牛的坐标与x[i]差的绝对值 的和(设为s_ans),最后乘以个v[i]即可,(这个应该就是枚举max了) ); 又可以避免重复计算距离

    思考难点(即简化后的题意): 已知是考树状数组的题目,又知它方便于求和。

    于是...我们点开了题解...

    定义:第i头牛前面有num头牛的x坐标比x[i]小,并且他们的和为sum

    思考得s_ans =i头牛前面的,xx[i]的牛对答案的贡献s1 +i头牛前面的,xx[i]的牛对答案的贡献s2

    s1 = num * a[i].x - sum;
    s2 = all - sum - a[i].x * (i-1-num);

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define lowbit(x) x&(-x)
    const int MAX = 20000+9;
    
    int n;
    long long ans;
    int t_n[MAX]/*num*/, t_sum[MAX];
    struct node{
    	int x, v;
    	bool operator < (const node& xx) const {
    		return v < xx.v;
    	}
    }a[MAX];
    
    void add(int x, int k, int *t) {
    	while(x <= MAX) t[x] += k, x += lowbit(x);//注意:坐标求和的右边界不是n 
    }
    int query(int x, int *t) {
    	int res = 0;
    	while(x) {res += t[x], x -= lowbit(x);}
    	return res;
    }
    
    int main() {
      freopen("01.in","r",stdin);
      freopen("01.out","w",stdout);
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i++) scanf("%d%d",&a[i].v, &a[i].x);
    	sort(a+1, a+1+n);
    	int all = 0, num, sum;
    	for(int i = 1; i <= n; i++) {
    		num = query(a[i].x, t_n);//先query再add,因为求的是i牛前面的 
    		sum = query(a[i].x, t_sum);
    		ans += (long long)( num*a[i].x-sum + all-sum-a[i].x*(i-1-num) )*a[i].v;
    		add(a[i].x, 1, t_n);
    		add(a[i].x, a[i].x, t_sum);//?
    		all += a[i].x;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [hdu1402]A * B Problem Plus(NTT)
    拦截导弹问题(Noip1999)
    删数问题(Noip1994)
    1217:棋盘问题
    随笔功能测试
    教师派8
    教师派7
    教师派6
    教师派5
    教室派4
  • 原文地址:https://www.cnblogs.com/tyner/p/11594566.html
Copyright © 2020-2023  润新知