http://www.51nod.com/Challenge/Problem.html#problemId=1712

先考虑题面中的简化问题。

对于\(i\in [1,n]\),\(a_i\)的贡献为\(a_i*(i-1)-a_i*(n-i)\)

那么对于\(i\in [l,r](a_l=a_r)\),贡献为\(a_i*(i-l)-a_i*(r-i)=2i*a_i-a_i(l+r)\)

这个式子只需要统计4个东西就可以\(O(n)\)计算了。

  • \(i\)左侧\(a_l\)的个数\(A\)
  • \(i\)右侧\(a_r\)的个数\(B\)
  • \(i\)左侧\(a_l\)的\(l\)之和\(C\)
  • \(i\)右侧\(a_r\)的\(r\)之和\(D\)

那么对答案的贡献就是\(2*i*a_i*A*B-a_i*(BC+AD)\)

统计一下\(A,B,C,D\)即可。

#include <bits/stdc++.h>
using namespace std; inline int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x * f;
} typedef unsigned int uint;
const int N = 1000010; int n, lim, a[N];
uint num[N], sum[N], numl[N], numr[N], suml[N], sumr[N];
uint Sum, Num; int main() {
n = read();
for(int i = 1; i <= n; ++i) {
a[i] = read();
numr[a[i]]++; sumr[a[i]] += i;
}
uint ans = 0;
for(int i = 1; i <= n; ++i) {
numl[a[i]]++; suml[a[i]] += i;
Num -= num[a[i]];
num[a[i]] = numl[a[i]] * numr[a[i]];
Num += num[a[i]];
Sum -= sum[a[i]];
sum[a[i]] = suml[a[i]] * numr[a[i]] + sumr[a[i]] * numl[a[i]];
Sum += sum[a[i]]; ans += 2 * i * a[i] * Num - a[i] * Sum; numr[a[i]]--; sumr[a[i]] -= i;
Num -= num[a[i]];
num[a[i]] = numl[a[i]] * numr[a[i]];
Num += num[a[i]];
Sum -= sum[a[i]];
sum[a[i]] = suml[a[i]] * numr[a[i]] + sumr[a[i]] * numl[a[i]];
Sum += sum[a[i]];
}
printf("%u\n", ans);
}

51nod1712 区间求和的更多相关文章

  1. POJ 2823 Sliding Window 线段树区间求和问题

    题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...

  2. POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)

    A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...

  3. vijos1740 聪明的质监员 (二分、区间求和)

    http://www.rqnoj.cn/problem/657 https://www.vijos.org/p/1740 P1740聪明的质检员 请登录后递交 标签:NOIP提高组2011[显示标签] ...

  4. LightOJ 1112 Curious Robin Hood (单点更新+区间求和)

    http://lightoj.com/volume_showproblem.php?problem=1112 题目大意: 1 i        将第i个数值输出,并将第i个值清0 2 i v     ...

  5. POJ 3468 A Simple Problem with Integers(线段树区间求和)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  6. poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)

    转载请注明出处:http://blog.csdn.net/u012860063 Description You have N integers, A1, A2, ... , AN. You need ...

  7. poj3468树状数组的区间更新,区间求和

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 47174   ...

  8. D 区间求和 [数学 树状数组]

    D 区间求和 题意:求 \[ \sum_{k=1}^n \sum_{l=1}^{n-k+1} \sum_{r=l+k-1}^n 区间前k大值和 \] 比赛时因为被B卡了没有深入想这道题 结果B没做出来 ...

  9. [用CDQ分治解决区间加&区间求和]【习作】

    [前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Par ...

随机推荐

  1. Centos 7.6 部署 Jumpserver 1.5.0

    1.基础设置 # 版本说明 操作系统:centos7. jumpserver: # 升级所有包同时也升级软件和系统内核 yum update -y # selinux配置 setenforce sed ...

  2. 分布式session一致性

    实现思路:当客户端发送请求到服务端后,在后台生成一个token,将token作为key,用户状态信息作为value,存入redis缓存中,并设置过期时间,最后把token返回给客户端 客户端第会保存t ...

  3. C++ 工程师养成 每日一题fourth (reverse的使用)

    题目: 将一句话的单词进行倒置,标点不倒置. 这道题最简单的解法是使用algorithm提供的reverse()函数 具体步骤我写在代码注释里面: #include <string> #i ...

  4. CLRS10.1-6练习 - 用双栈实现队列

    双栈实现队列算法: 分别考虑队列两种操作入队和出队,我们假设使用栈s1 s2, s1用来模拟入队,s2用来模拟出队 入队: 入队操作直接执行s1.push即可 出队: 代码实现 package hel ...

  5. .net 生成非托管代码

    最近在一个老外的程序中看到一段代码,其中使用了System.Runtime.InteropServices.MarshalAs方法进行托管代码与非托管代码之间封装数据,感觉很新颖.特意记录下来,供大家 ...

  6. 多次执行echarts时出现 there is a chart instance already initialized on the dom

    原因,多次使用 echarts.init(document.getElementById(this.options.zid)); 解决方案 设为全局

  7. ELK学习笔记之Logstash不停机自动重载配置文件

    0x00 自动重新加载配置 为了可以自动检测配置文件的变动和自动重新加载配置文件,需要在启动的时候使用以下命令: ./bin/lagstash -f configfile.conf --config. ...

  8. js 杂症,this with 变量提升

    一.this.xx 和 xx 是两回事 受后端语言影响,总把this.xx 和xx 当中一回事,认为在function中,xx 就是this.xx,其实完全两回事: this.xx 是沿着this 原 ...

  9. 2019-07-22 phpStudy配置虚拟主机

    1.右击 phpStudy ->[打开配置文件]->[vhosts-conf]: 2.在里面加入如下代码,并保存: NameVirtualHost *:80 <VirtualHost ...

  10. 必须修改getdate()格式,判断是否处于两个日期之间

    ), ) ), )<= 周次结束日期 ), ) -- 这样的格式结果为:2019-09-01 --如果不进行转换,查出来含有日期和时间,否则两个边界无法查询出来